So here is my code for the 3n+1 problem on UVa. It runs perfectly on my PC in Eclipse AFAIK, however, I keep getting a runtime error against the UVa judge. Unfortunately, the judge does not tell me what inputs it uses, nor provide any information beyond "RuntimeException" when it fails. This is the same structure as the ACM's ICPC, for the curious.
I am pretty sure that the recursion shall not overflow the stack as the maximum cycle length of all numbers from 1 to 1000000 is only 525. Also, the cache of 1000000 integers shall be only 4Mb large.
package Collatz;
import java.util.Arrays;
import java.util.Scanner;
class Main{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] cache = buildCache(1000000);
while (in.hasNextLine()) {
Scanner line = new Scanner(in.nextLine());
if (!line.hasNextInt()) continue;
int a = line.nextInt();
int b = line.nextInt();
int c = a;
int d = b;
if (c > d) {
int temp = c;
c = d;
d = temp;
}
int max = 0;
for (int i = c - 1; i <= d - 1; i++) {
max = Math.max(max, cache[i]);
}
System.out.format("%d %d %d\n", a, b, max);
line.close();
}
in.close();
}
public static int[] buildCache(int n) {
int[] cache = new int[n];
Arrays.fill(cache, 0);
cache[0] = 1;
for (int i = 1; i < n; i++) {
search(i + 1, cache);
}
return cache;
}
public static int search(long i, int[] cache) {
int n = cache.length;
if (i == 1) {
return 1;
} else if (i <= n && cache[(int)(i - 1)] > 0) {
return cache[(int)(i - 1)];
} else {
long j = (i % 2 == 1) ? (3 * i + 1) : (i / 2);
int result = search(j, cache) + 1;
if (i <= n) {
cache[(int)(i - 1)] = result;
}
return result;
}
}
}
OK. I finally found the problem. It is the package statement. The program is accepted after removing it... A bit mistake for me when copy-paste code from my IDE to submission form.. But there are some interesting discussions here and thank everyone!
The logic here will overflow the stack. It goes searching for the next number in the sequence before caching the result of the function on the current one.
int result = search(j, cache) + 1;
if (i <= n) {
cache[(int)(i - 1)] = result;
}
return result;
Related
Trying to solve this problem with recursion and memoization but for input 7168 I'm getting wrong answer.
public int numSquares(int n) {
Map<Integer, Integer> memo = new HashMap();
List<Integer> list = fillSquares(n, memo);
if (list == null)
return 1;
return helper(list.size()-1, list, n, memo);
}
private int helper(int index, List<Integer> list, int left, Map<Integer, Integer> memo) {
if (left == 0)
return 0;
if (left < 0 || index < 0)
return Integer.MAX_VALUE-1;
if (memo.containsKey(left)) {
return memo.get(left);
}
int d1 = 1+helper(index, list, left-list.get(index), memo);
int d2 = 1+helper(index-1, list, left-list.get(index), memo);
int d3 = helper(index-1, list, left, memo);
int d = Math.min(Math.min(d1,d2), d3);
memo.put(left, d);
return d;
}
private List<Integer> fillSquares(int n, Map<Integer, Integer> memo) {
int curr = 1;
List<Integer> list = new ArrayList();
int d = (int)Math.pow(curr, 2);
while (d < n) {
list.add(d);
memo.put(d, 1);
curr++;
d = (int)Math.pow(curr, 2);
}
if (d == n)
return null;
return list;
}
I'm calling like this:
numSquares(7168)
All test cases pass (even complex cases), but this one fails. I suspect something is wrong with my memoization but cannot pinpoint what exactly. Any help will be appreciated.
You have the memoization keyed by the value to be attained, but this does not take into account the value of index, which actually puts restrictions on which powers you can use to attain that value. That means that if (in the extreme case) index is 0, you can only reduce what is left with one square (1²), which rarely is the optimal way to form that number. So in a first instance memo.set() will register a non-optimal number of squares, which later will get updated by other recursive calls which are pending in the recursion tree.
If you add some conditional debugging code, you'll see that map.set is called for the same value of left multiple times, and with differing values. This is not good, because that means the if (memo.has(left)) block will execute for cases where that value is not guaranteed to be optimal (yet).
You could solve this by incorporating the index in your memoization key. This increases the space used for memoization, but it will work. I assume you can work this out.
But according to Lagrange's four square theorem every natural number can be written as the sum of at most four squares, so the returned value should never be 5 or more. You can shortcut the recursion when you get passed that number of terms. This reduces the benefit of using memoization.
Finally, there is a mistake in fillSquares: it should add n itself also when it is a perfect square, otherwise you'll not find solutions that should return 1.
Not sure about your bug, here is a short dynamic programming Solution:
Java
public class Solution {
public static final int numSquares(
final int n
) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
int min = Integer.MAX_VALUE;
while (i - j * j >= 0) {
min = Math.min(min, dp[i - j * j] + 1);
++j;
}
dp[i] = min;
}
return dp[n];
}
}
C++
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
#define MAX INT_MAX
using ValueType = std::uint_fast32_t;
struct Solution {
static const int numSquares(
const int n
) {
if (n < 1) {
return 0;
}
static std::vector<ValueType> count_perfect_squares{0};
while (std::size(count_perfect_squares) <= n) {
const ValueType len = std::size(count_perfect_squares);
ValueType count_squares = MAX;
for (ValueType index = 1; index * index <= len; ++index) {
count_squares = std::min(count_squares, 1 + count_perfect_squares[len - index * index]);
}
count_perfect_squares.emplace_back(count_squares);
}
return count_perfect_squares[n];
}
};
int main() {
std::cout << std::to_string(Solution().numSquares(12) == 3) << "\n";
return 0;
}
Python
Here we can simply use lru_cache:
class Solution:
dp = [0]
#functools.lru_cache
def numSquares(self, n):
dp = self.dp
while len(dp) <= n:
dp += min(dp[-i * i] for i in range(1, int(len(dp) ** 0.5 + 1))) + 1,
return dp[n]
Here are LeetCode's official solutions with comments:
Java: DP
class Solution {
public int numSquares(int n) {
int dp[] = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// bottom case
dp[0] = 0;
// pre-calculate the square numbers.
int max_square_index = (int) Math.sqrt(n) + 1;
int square_nums[] = new int[max_square_index];
for (int i = 1; i < max_square_index; ++i) {
square_nums[i] = i * i;
}
for (int i = 1; i <= n; ++i) {
for (int s = 1; s < max_square_index; ++s) {
if (i < square_nums[s])
break;
dp[i] = Math.min(dp[i], dp[i - square_nums[s]] + 1);
}
}
return dp[n];
}
}
Java: Greedy
class Solution {
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
this.square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
this.square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
}
Java: Breadth First Search
class Solution {
public int numSquares(int n) {
ArrayList<Integer> square_nums = new ArrayList<Integer>();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
Set<Integer> queue = new HashSet<Integer>();
queue.add(n);
int level = 0;
while (queue.size() > 0) {
level += 1;
Set<Integer> next_queue = new HashSet<Integer>();
for (Integer remainder : queue) {
for (Integer square : square_nums) {
if (remainder.equals(square)) {
return level;
} else if (remainder < square) {
break;
} else {
next_queue.add(remainder - square);
}
}
}
queue = next_queue;
}
return level;
}
}
Java: Most efficient solution using math
Runtime: O(N ^ 0.5)
Memory: O(1)
class Solution {
protected boolean isSquare(int n) {
int sq = (int) Math.sqrt(n);
return n == sq * sq;
}
public int numSquares(int n) {
// four-square and three-square theorems.
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
if (this.isSquare(n))
return 1;
// enumeration to check if the number can be decomposed into sum of two squares.
for (int i = 1; i * i <= n; ++i) {
if (this.isSquare(n - i * i))
return 2;
}
// bottom case of three-square theorem.
return 3;
}
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I am trying to write a recursive algorithm to compute Fibonacci numbers. However, the program struggles with printing out the results.
My idea was to store each calculated value into an array (so the algorithm should be faster).
My desired output:
The fibonacci of n = 1 is fn= 1
The fibonacci of n = 2 is fn= 2
The fibonacci of n = 3 is fn= 2
The fibonacci of n = 4 is fn= 3
...
The fibonacci of n = 8 is fn= 21
public class fibonacciCalculator {
static int[] arr = new int[50];
static int fibo (int n, int arr[]) {
if ( n == 0 ) {
return 0;
}else if ( n == 1 ) {
return 1;
}
if ( arr[n-1] == 0) {
arr[n-1] = fibo(n-1, arr);
}
if ( arr[n-2] == 0) {
arr[n-2] = fibo(n-2, arr);
}
return arr[n-1] + arr[n - 2];
}
public static void main(String[] args) {
for (int i = 1; i == 8; i++) {
if (arr [i] == 0) {
fibo(i, arr);
int x = arr[i];
String a = String.format("The fibonacci of n = %d is fn= %d", i , x);
System.out.println(a);
}
}
}
}
You can do this without declaring an array. This way, the intermediate values are stored in the execution stack:
public class fibonacciCalculator {
static int fibo (int n) {
if ( n == 0 ) {
return 0;
} else if ( n == 1 ) {
return 1;
} else {
return fibo(n-2) + fibo(n-1);
}
}
public static void main(String[] args) {
for (int i = 1; i <= 8; i++) {
int x = fibo(i);;
String a = String.format("The fibonacci of n = %d is fn= %d", i , x);
System.out.println(a);
}
}
}
Here is one way to do it.
public int[] fib(int values[], int count) {
if (count <= 0) {
return values;
}
int k = values.length + 1;
values = Arrays.copyOf(values, k);
values[k - 1] = values[k - 2] + values[k - 3];
return fib(values, count - 1);
}
But an even better way is to memoize the values as you create them. This permits you to start calculating at the last computed terms and then continue until you meet your goal. If you specify a value less than the number computed, only those requested are returned.
A defensive copy of the list is used so you can't taint the returned sublist.
List<Integer> fibs = new ArrayList(List.of(0, 1));
public List<Integer> fib(int count) {
int s = fibs.size();
if (count < s) {
// return a defensive copy to protect cached values.
return new ArrayList<>(fibs.subList(0, count));
}
int e = fibs.get(s - 1) + fibs.get(s - 2);
fibs.add(e);
return fib(count);
}
Okay to close this up I will post the working code.
Maybe that will help anyone else.
public class fibonacciCalculator {
static int[] arr = new int[48];
static int fibo (int n, int arr[]) {
if ( n == 1|| n == 2 ) {
return 1;
}else if ( n == 0 ) {
return 0;
}
if (arr[n-1] == 0) {
arr[n-1] = fibo(n-1, arr);
}
if (arr[n-2] == 0) {
arr[n-2] = fibo(n-2, arr);
}
return arr[n-1] + arr[n - 2];
}
public static void main(String[] args) {
for (int i = 1; i <= arr.length-1; i++) {
if (arr [i] == 0) {
arr[i] = fibo(i, arr);
System.out.print("The Fibonacci number " + i);
System.out.println(" is: " + arr[i]);
}
}
}
}
However ... int will exceed its limit at Fibonacci 48. If you want higher values int should be replaced to long.
but after that well don't know.. :D
Greetings Synix
I have the following program
The sum of squares 1^2 + 2^2 + … + N^2 is calculated as:
Example output:
java SumSquares 2 = 5
java SumSquares 3 = 14
java SumSquares 1000000 = 333333833333500000
Here's what I have so far:
int N = Integer.parseInt(args[0]);
int sum = 0;
long R;
for (int i = 1; i <= N; i++) {
R = i * i;
if (i != R / i) {
System.err.println("Overflow at i = " + i);
System.exit(1);
}
sum += R;
}
System.out.println(sum);
My output is java SumSquares 100000000
Overflow at i = 46341
As 46341^2 passes MAX INT.
I just can't get the program to out put the below instructions, any ideas on how to get
java SumSquares 100000000
Overflow at i = 3024616
I could change the ints to longs but that would negate the need for the overflow checking.
From specification:
The computation will overflow. I need to exactly determine the point in the summation where the overflow happens, via checking whether the new sum is (strictly) less than the old sum.
java SumSquares 100000000
Overflow at i = 3024616
Note that the above must be achieved by a general overflow-handling in the loop, not by some pre-determined input-testing. So that when the integer-type used for the summation is replaced by some bigger type, your program will fully use the new extended range.
Just to clarify:
Is it possible to get the output
java SumSquares 100000000
Overflow at i = 3024616
As per the specification.
You have 2 errors:
R = i * i still performs the multiplication using int math, and doesn't widen the value to long until after multiplication has already overflowed to a negative value.
You need to cast at least one of them to long, e.g. R = i * (long) i.
if (i != R / i) is not the right test for overflow. Simply check if the long value exceeds the range of int: if (r > Integer.MAX_VALUE)
static int sumOfSquares(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) {
long r = i * (long) i;
if (r > Integer.MAX_VALUE) {
System.err.println("Overflow at i = " + i);
System.exit(1);
}
sum += r;
}
return sum;
}
Test
System.out.println(sumOfSquares(2));
System.out.println(sumOfSquares(3));
System.out.println(sumOfSquares(1000000));
Output
5
14
Overflow at i = 46341
Another way to guard against overflow is to use the Math.multiplyExact() and Math.addExact() methods.
static int sumOfSquares(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) {
int r = Math.multiplyExact(i, i);
sum = Math.addExact(sum, r);
}
return sum;
}
Output
5
14
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.base/java.lang.Math.addExact(Math.java:825)
at Test.sumOfSquares(Test.java:12)
at Test.main(Test.java:6)
Or catch the exception if you want a better error message:
static int sumOfSquares(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) {
try {
int r = Math.multiplyExact(i, i);
sum = Math.addExact(sum, r);
} catch (#SuppressWarnings("unused") ArithmeticException ignored) {
System.err.println("Overflow at i = " + i);
System.exit(1);
}
}
return sum;
}
Output
5
14
Overflow at i = 1861
Without having to use longs, you can check if the multiplication of two integers will overflow before actually doing the operation:
int a = 500000; //or -500000
int b = 900000; //or -900000
System.out.println(isOverflowOrUnderflow(a, b));
//Returns true if multiplication of a, b results in an overflow or underflow..
public static boolean isOverflowOrUnderflow(int a, int b) {
return ((a > Integer.MAX_VALUE / b) || (a < Integer.MIN_VALUE / b) || ((a == -1) && (b == Integer.MIN_VALUE)) || ((b == -1) && (a == Integer.MIN_VALUE)));
}
Example using your code:
public class Main {
public static void main (String[] args) {
int N = Integer.parseInt(args[0]); //Where args[0] = "1000000"..
int sum = 0;
long R;
for (int i = 1; i <= N; i++) {
if (Main.isOverflowOrUnderflow(i, i)) {
System.err.println("Overflow at i = " + i);
System.exit(1);
}
R = i * i;
sum += R;
}
System.out.println(sum);
}
public static boolean isOverflowOrUnderflow(int a, int b) {
return ((a > Integer.MAX_VALUE / b) || (a < Integer.MIN_VALUE / b) || ((a == -1) && (b == Integer.MIN_VALUE)) || ((b == -1) && (a == Integer.MIN_VALUE)));
}
}
Outputs:
Overflow at i = 46341
Command exited with non-zero status 1
import java.util.Scanner;
import java.io.*;
class factorial {
void fact(int a) {
int i;
int ar[] = new int[10000];
int fact = 1, count = 0;
for (i = 1; i <= a; i++) {
fact = fact * i;
}
String str1 = Integer.toString(fact);
int len = str1.length();
i = 0;
do {
ar[i] = fact % 10;
fact /= 10;
i++;
} while (fact != 0);
for (i = 0; i < len; i++) {
if (ar[i] == 0) {
count = count + 1;
}
}
System.out.println(count);
}
public static void main(String...ab) {
int a;
Scanner input = new Scanner(System.in);
a = input.nextInt();
factorial ob = new factorial();
ob.fact(a);
}
}
This code is work up to a = 10 but after enter number larger then a = 16 it gives wrong answer.
Please help.
As I am not able to post this question if I dont add more info for this question but I assume that the info I provide above is enough to under stand what I want.
Like many of these mathematical puzzles, you are expected to simplify the problem to make it practical. You need to find how many powers of ten in a factorial, not calculate a factorial and then find the number of trailing zeros.
The simplest solution is to count the number of powers of five. The reason you only need to count powers of five is that there is plenty of even numbers in between then to make a 10. For example, 5! has one 0, 10! has 2, 15! has three, 20! has four, and 25! has not five but six as 25 = 5 * 5.
In short you only need calculate the number of powers of five between 1 and N.
// floor(N/5) + floor(N/25) + floor(N/125) + floor(N/625) ...
public static long powersOfTenForFactorial(long n) {
long sum = 0;
while (n >= 5) {
n /= 5;
sum += n;
}
return sum;
}
Note: This will calculate the trailing zeros of Long.MAX_VALUE! in a faction of a second, whereas trying this with BigInteger wouldn't fit, no matter how much memory you had.
Please Note, this is not the mathematical solution as others suggested, this is just a refactoring of what he had initially...
Here I just used BigInteger in place of Int, and simplified your code abit. Your solution is still not optimal. I thought I would just show you what a refactored version of what you posted may look like. Also there was a bug in your initial function. It returned the number of zeros in the whole number instead of just the number of trailing zeros.
import java.math.BigInteger;
import java.util.Scanner;
class factorial {
public static void main(String... ab) {
Scanner input = new Scanner(System.in);
int a = input.nextInt();
fact(a);
}
private static void fact(int a) {
BigInteger fact = BigInteger.ONE;
int i, count = 0;
for (i = 1; i <= a; i++) {
fact = fact.multiply(new BigInteger(Integer.toString(i)));
}
String str1 = fact.toString();
for(int j = str1.length() - 1; j > -1; j--) {
if(Character.digit(str1.charAt(j), 10) != 0) {
System.out.println(count);
break;
} else {
count++;
}
}
}
}
Without using factorial
public class TrailingZero {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(trailingZeroes(9247));
}
public static int trailingZeroes(int a) {
int countTwo = 0;
int countFive = 0;
for (int i = a; i > 1; i--) {
int local = i;
while (local > 1) {
if (local % 2 != 0) {
break;
}
local = local / 2;
countTwo++;
}
while (local > 1) {
if (local % 5 != 0) {
break;
} else {
local = local / 5;
countFive++;
}
}
}
return Math.min(countTwo, countFive);
}}
i am trying some math-operations with java, that does test a number if its (un)even and alter it as long as it gets to 1.
I try to run my loop for 999999times, it seems to get stuck at around ~120000times. Well, it is not stopping with an Exception, it just feels like the compiler got stuck.
I'm not that good with Java, can someone explain me what is happening here?
public static void main(String[] args) {
int n = 0;
int highestNumber = 0;
int highestCounter = 0;
int counter = 0;
for (int i = 2;i<1000000;i++) {
if (i%10000==0) {
System.out.println(i);
}
n = i;
while (n!=1) {
if (n%2==0) {
n = n/2;
} else {
n=3*n+1;
}
counter++;
}
if (counter>highestCounter) {
highestCounter = counter;
highestNumber = i;
System.out.println("HIGHEST "+highestNumber+" | counter = "+counter);
}
counter = 0;
n = 0;
}
System.out.println("final "+highestNumber);
}
You've got an overflow because 3 * n + 1 became larger than Integer.MAX_VALUE. So n gets negative and the while loop will never halt.
Use long instead of int for n!
If you want to check for the overflow instead:
while (n != 1) {
if (n % 2 == 0) {
n = n / 2;
} else {
if (n > (Integer.MAX_VALUE - 1) / 3) {
throw new RuntimeException("overflow!");
}
n = 3 * n + 1;
}
counter++;
}
Addition for Java 8
Since Java 8, the Math class provides additional static methods for 'exact' arithmetics (addition, subtraction, multiplication, division) that throw an ArithmeticException in case of an overflow. Using these methods, the code can be simplified:
while (n != 1) {
if (n % 2 == 0) {
n = n / 2;
} else {
n = Math.addExact(Math.multiplyExact(3, n), 1);
}
counter++;
}
You have an overflow problem. Change the code like this and you see it:
while (n!=1) {
if(n < 0) throw new IllegalStateException("n should not become < 0" + n + "-" + counter);
if(n > ((Integer.MAX_VALUE -1) / 3)) System.out.println("n too large. " + n);
if (n%2==0) {
n = n/2;
} else {
n=3*n+1;
}
counter++;
}
if you make n to a long it works fine.
This correction works:
public static void main(String []args){
long highestCounter = -1;
long highestNumber = -1;
for (long i = 2;i<1000000;i++) {
if (i%1000==0) {
System.out.println(i);
}
long n = i;
long counter = 0;
while (n!=1) {
if (n%2==0) {
n = n/2;
} else {
n=3*n+1;
}
counter++;
}
if (counter>highestCounter) {
highestCounter = counter;
highestNumber = i;
System.out.println("HIGHEST "+highestNumber+" | counter = "+counter);
}
counter = 0;
n = 0;
}
System.out.println("final "+highestNumber);
}
Hmm, your code looks fine to me. You're solving a pretty typical problem
Is n an integer? If it's a short you might be overflowing it.
Other than that, an integer's max value is over 2 billion, so you shouldn't be hitting it. Just in case, try setting n to a long to see if that helps
Edit: Take for example, the number 77671 According to a blog I read (read: untested) the highest n for i = 77671 is 1,047,216,490
So I think n should be a long, now that I think more about it
You simply running an infinite loop inside while block, add System.out.println(counter); after counter++ to see what's going on..