Calculate Large Factorials Using Nodes in Java - java

Okay, so I have been searching the internet and have found many things related to this question. However, I am not able to put the pieces together in order to figure this out.
The requirements are to calculate a large factorial (e.g. 999!) USING LINKED LISTS and NODES. There are many people online that have shown a basic way of calculating a factorial and I understand how to do the factorial part, but the part I am having trouble with is filling each node with an Int between 0-999 (a three digit number) then printing out each node to look like a whole number (including commas).
How can I achieve this?
- My thoughts are to get the result of n! and just do %10, %100,etc.. to break it up and insert the parts into nodes, but that would be pointless because the factorial would have to be completely solved for that to work. So that would be dumb.
The reason for doing this is to learn how to manipulate nodes and linked lists for my Data Structures class.
To me, this a clear explanation, but please let me know if the question is unclear and I will try to explain. Any help will be much appreciated.
(I dont have any code to show besides a basic factorial function that I am using as a bases to build upon).

Okay, I think I understand what you're after.
At the end of this answer is a link to a Gist that solves this problem. I'm not entirely sure it's what you are after, alas... it's my best guess.
The algorithm consists of five steps:
Build the list of factorial members.
Calculate and group Prime Factors of factorial members.
Distribute Prime Factors over powers of 10.
Multiply Prime Factors, carrying overflow up into the next decimal
place.
Print the solution.
It is inspired by the method described here on math.stackexchange.com. I strongly suggest reading both the question and answer linked before examining the Gist.
Now that that's been said, the Gist can be found here. It is very rough, meant only as a quick demonstration of the method.
I hope it helps you. Best of luck.

To calculate a factorial using a LinkedList is a simple 2-stage process.
Stage 1 is to create a LinkedList of all numbers up to the number you want the factorial of. This is a very simple operation that can be achieved with a basic for loop.
List<Integer> list = new LinkedList<Integer>();
for(int i = 1; i <= limit; i++) {
list.add(i);
}
System.out.println(list);
Stage 2 is also relatively easy, using a foreach loop, we iterate over the contents of the list and multiply each element by the product of the previous list elements.
One major concern however, is that the factorial of numbers as large as 999 cannot be held in any of Java's primitive numeric types (int or even long). To hold the factorial, we have to make use of Java's BigDecimal class (Java Docs).
//Stage 2: Calculate the factorial.
BigDecimal factorial = new BigDecimal(1);
BigDecimal factor = null;
for(int n : list) {
factor = new BigDecimal(n);
factorial = factorial.multiply(factor);
}
With those two stages, we can simply print the contents of factorial to see the factorial of your provided number. See the complete code below:
public static void factorial(int limit) {
// Stage 1: Build the list.
List<Integer> list = new LinkedList<Integer>();
for(int i = 1; i <= limit; i++) {
list.add(i);
}
System.out.println(list);
//Stage 2: Calculate the factorial.
BigDecimal factorial = new BigDecimal(1);
BigDecimal factor = null;
for(int n : list) {
factor = new BigDecimal(n);
factorial = factorial.multiply(factor);
}
System.out.println(factorial);
}

We multiply like we actually do with every digit of the number and take take the carry forward. Each digit is stored in a node of the linkedlist. The number is stored in reverse order so that we can multiply without using any extra space.
public static void find(int n) {
Node head=new Node(1);
for(int i=2;i<=n;i++)
multiply(i,head);
print(head);
}
private static void multiply(int k, Node head) {
int carry=0,prod=0;
Node prev=null;
while(head!=null)
{
prod=head.data*k+carry;
head.data=prod%10;
carry=prod/10;
prev=head;
head=head.next;
}
while(carry!=0) {
Node n=new Node(carry%10);
prev.next=n;
carry=carry/10;
prev=prev.next;
}
}
private static void print(Node head) { //printing in reverse order
if(head==null)
return;
print(head.next);
System.out.print(head.data);
}
The concept is best explained here

Related

Java finding all combos in array that add up to specific number [duplicate]

This question already has an answer here:
Finding all the number combos in array that add up to input number
(1 answer)
Closed 6 years ago.
I'm currently working on the following question from a interviewing book:
You are given a random array of 50 unique integers ranging from 1 to 100 inclusive. Write a method using Java that takes in a positive integer as a parameter and returns an array of all the number combinations that add up to that value.
For example, given an array of integers [3,6,1,9,2,5,12] and being passed the integer value 9, you would return [[3,6],[6,1,2],[9],[3,1,5]]. Order of returning the results in the array does not matter, though you should return unique sets (ie. [6,3] and [3,6] are the same and only one should be returned). Also, the individual results should be in the order they are found (ie [6,1,2] should be returned, not [1,2,6]).
I've made decent progress on it, but I fear I may solving this the wrong way.
import java.util.*;
public class findCombinations {
public static void main(String[] args) {
int number;
int[] list = new int[10];
Scanner reader = new Scanner(System.in);
//fill the array
for (int i = 0; i < list.length; i++) {
number = (int)(Math.random() * 10) + 1;
list[i] = number;
for (int j = 0; j < i; j++) { //remove duplicates
if (list[i] == list[j]) {
i--;
break;
}
}
}
Arrays.sort(list);
//test output
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
}
System.out.println("Enter a number: ");
int input = reader.nextInt();
ArrayList<Integer> trimmedList = new ArrayList<Integer>();
//cut out the numbers that are impossible to use
for (int i = 0; i < list.length; i++) {
if (list[i] <= input) {
trimmedList.add(list[i]);
}
}
//test output
printList(trimmedList);
ArrayList<Integer> comboList = new ArrayList<Integer>();
System.out.println("Finding combinations...");
for (int i = 0; i < trimmedList.size(); i++) {
int current = trimmedList.get(i);
if (current == input) { System.out.println(current); }
else if (current < input) {
comboList.add(current);
if (isCombo(comboList, input)) {
printList(comboList);
}
else { continue; }
}
else { continue; }
}
}
public static boolean isCombo(ArrayList<Integer> list, int input) {
ArrayList<Integer> combo = new ArrayList<Integer>();
int sum = 0;
for (int i : list)
sum += i;
if (sum == input) { return true; }
else { return false; }
}
public static void printList(ArrayList<Integer> list) {
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));
}
}
}
I know this is incomplete but I wanted to ask if anyone had any suggestions or improvements I could make on this? I sorted my list and trimmed out all the integers that won't possibly be used, but now the hard part is finding all the combos.
There are many different approaches to solve this problem, each with their own merits, so I wouldn't worry too much about whether your answer is the 'right' one or not...so long as it actually solves the problem! Also, an interviewer will likely be more interested in your thought-process, and the strategies you use, rather than a 100% perfect solution written in the span of a few minutes on a whiteboard.
Here's a couple of things to consider:
As you noticed, you can immediately eliminate any integers larger than your target value.
You're essentially generating arbitrarily-sized subsets of your starting array—so Set is likely the most useful data type to work with. {2, 3} and {3, 2} should be seen as identical when you're generating your response set.
Integer partitioning is an NP-Complete problem. It's hard. I think you've taken the correct approach of starting with the array, rather than with the target value.
There are many algorithms for generating combinations of integers from a larger set. Check out this SO answer for a few of them. You can generate k sized combinations from your (already-filtered) starting set, for k from 1-50.
Actually...there are more direct ways to get the power set of your starting set. Consider the inherent structure of a power set (shown below). By enumerating a few examples, you'll notice a natural recurrence in your strategy for identifying the subsets.
As you're generating these combinations, discard any whose elements don't sum to your target value.
Image Source: https://en.wikipedia.org/wiki/Power_set
Since this is a learning exercise, you will benefit most if you can solve this for yourself. So ...
Hints:
Sorting the numbers first is on the right track
I would use recursion to iterate the solutions. Given a partial sum, only numbers less than a certain number are possible candidates to be added to the sum ...
Work out the algorithm in your head >before< you start coding it.
And I agree with what #nbrooks says on the topic of what the interviewers are looking for. You need to be able to think ... and explain your thinking to the interviewer ... at the algorithmic level. That is what will distinguish the excellent candidates from the ordinary ones.
I realize generating your array of random numbers is not part of the problem statement, but I think your difficulties begin here.
First of all, use a Set<Integer> type collection to collect your generated numbers; break when the set reaches the desired size. If generated order is important, use a LinkedHashSet.
Set<Integer> origSet = new HashSet<Integer>(); // fill with random numbers
At some point, you have a list of numbers for which the order matters. Maintain this list as a List<Integer>. The list preserves the order of your original list so that you can produce the number combinations in the right order (i.e., 6 precedes 1, 1 precedes 2).
List<Integer> origList = new ArrayList<Integer>(origSet); // use indexOf method to find index of a number
You create a second list that is sorted; this list is the one used by your recursion algorithm.
List<Integer> sortedList = new ArrayList<Integer>(origList); // sort this
You don't need to trim the list because a recursive algorithm will trim any branch with no feasible solution.
A recursive algorithm can generate the combos in fewer lines of code. Reordering takes a few more lines.

Using an array of precomputed powers to extract roots

I am writing a program that solves a sum of tenth powers problem and I need to have a fast algorithm to find n^10 as well as n^(1/10) For natural n<1 000 000. I am precomputing an array of powers, so n^10 (array lookup) takes O(1). For n^(1/10) I am doing a binary search. Is there any way to accelerate extraction of a root beyond that? For example, making an array and filling elements with corresponding roots if the index is a perfect power or leaving zero otherwise would give O(1), but I will run out of memory. Is there a way to make root extraction faster than O(log(n))?
Why should the array of roots run out of memory? If it is the same size as the array of powers, it will fit using the same datatypes. However for the powers, (10^6)^10 = 10^60, which does not fit into a long variable so you need to use biginteger or bigdecimal types. In case your number n is bigger than the biggest array size n_max your memory can afford, you can divide n by n_m until it fits, i.e. split n = n_max^m*k, where m is a natural number and k < n_max:
public class Roots
{
static final int N_MAX = 1_000_000;
double[] roots = new double[N_MAX+1];
Roots() {for (int i = 0; i <= N_MAX; i++) {roots[i] = Math.pow(i, 0.1);}}
double root(long n)
{
int m = 0;
while (n > N_MAX)
{
n /= N_MAX;
m++;
}
return (Math.pow(roots[N_MAX],m)*roots[(int)n]); // in a real case you would precompute pow(roots[N_MAX],m) as well
}
static public void main(String[] args)
{
Roots root = new Roots();
System.out.println(root.root(1000));
System.out.println(root.root(100_000_000_000_000l));
}
}
Apart LUT You got two options to speed up I can think of:
use binary search without multiplication
If you are using bignums then 10th-root binary search search is not O(log(n)) anymore as the basic operation used in it are no longer O(1) !!! For example +,-,<<,>>,|,&,^,>=,<=,>,<,==,!= will became O(b) and * will be O(b^2) or O(b.log(b)) where b=log(n) depending on algorithm used (or even operand magnitude). So naive binary search for root finding will be in the better case O(log^2(n).log(log(n)))
To speedup it you can try not to use multiplication. Yes it is possible and the final complexity will bee O(log^2(n)) Take a look at:
How to get a square root for 32 bit input in one clock cycle only?
To see how to achieve this. The difference is only in solving different equations:
x1 = x0+m
x1^10 = f(x0,m)
If you obtain algebraically x1=f(x0,m) then each multiplication inside translate to bit-shifts and adds... For example 10*x = x<<1 + x<<3. The LUT table is not necessary as you can iterate it during binary search.
I imagine that f(x0,m) will contain lesser powers of x0 so analogically compute all the needed powers too ... so the final result will have no powering. Sorry too lazy to do that for you, you can use some math app for that like Derive for Windows
you can use pow(x,y) = x^y = exp2(y*log2(x))
So x^0.1 = exp2(log2(x)/10) But you would need bigdecimals for this (or fixed point) here see how I do it:
How can I write a power function myself?
For more ideas see this:
Power by squaring for negative exponents

Find all the ways you can go up an n step staircase if you can take k steps at a time such that k <= n

This is a problem I'm trying to solve on my own to be a bit better at recursion(not homework). I believe I found a solution, but I'm not sure about the time complexity (I'm aware that DP would give me better results).
Find all the ways you can go up an n step staircase if you can take k steps at a time such that k <= n
For example, if my step sizes are [1,2,3] and the size of the stair case is 10, I could take 10 steps of size 1 [1,1,1,1,1,1,1,1,1,1]=10 or I could take 3 steps of size 3 and 1 step of size 1 [3,3,3,1]=10
Here is my solution:
static List<List<Integer>> problem1Ans = new ArrayList<List<Integer>>();
public static void problem1(int numSteps){
int [] steps = {1,2,3};
problem1_rec(new ArrayList<Integer>(), numSteps, steps);
}
public static void problem1_rec(List<Integer> sequence, int numSteps, int [] steps){
if(problem1_sum_seq(sequence) > numSteps){
return;
}
if(problem1_sum_seq(sequence) == numSteps){
problem1Ans.add(new ArrayList<Integer>(sequence));
return;
}
for(int stepSize : steps){
sequence.add(stepSize);
problem1_rec(sequence, numSteps, steps);
sequence.remove(sequence.size()-1);
}
}
public static int problem1_sum_seq(List<Integer> sequence){
int sum = 0;
for(int i : sequence){
sum += i;
}
return sum;
}
public static void main(String [] args){
problem1(10);
System.out.println(problem1Ans.size());
}
My guess is that this runtime is k^n where k is the numbers of step sizes, and n is the number of steps (3 and 10 in this case).
I came to this answer because each step size has a loop that calls k number of step sizes. However, the depth of this is not the same for all step sizes. For instance, the sequence [1,1,1,1,1,1,1,1,1,1] has more recursive calls than [3,3,3,1] so this makes me doubt my answer.
What is the runtime? Is k^n correct?
TL;DR: Your algorithm is O(2n), which is a tighter bound than O(kn), but because of some easily corrected inefficiencies the implementation runs in O(k2 × 2n).
In effect, your solution enumerates all of the step-sequences with sum n by successively enumerating all of the viable prefixes of those step-sequences. So the number of operations is proportional to the number of step sequences whose sum is less than or equal to n. [See Notes 1 and 2].
Now, let's consider how many possible prefix sequences there are for a given value of n. The precise computation will depend on the steps allowed in the vector of step sizes, but we can easily come up with a maximum, because any step sequence is a subset of the set of integers from 1 to n, and we know that there are precisely 2n such subsets.
Of course, not all subsets qualify. For example, if the set of step-sizes is [1, 2], then you are enumerating Fibonacci sequences, and there are O(φn) such sequences. As k increases, you will get closer and closer to O(2n). [Note 3]
Because of the inefficiencies in your coded, as noted, your algorithm is actually O(k2 αn) where α is some number between φ and 2, approaching 2 as k approaches infinity. (φ is 1.618..., or (1+sqrt(5))/2)).
There are a number of improvements that could be made to your implementation, particularly if your intent was to count rather than enumerate the step sizes. But that was not your question, as I understand it.
Notes
That's not quite exact, because you actually enumerate a few extra sequences which you then reject; the cost of these rejections is a multiplier by the size of the vector of possible step sizes. However, you could easily eliminate the rejections by terminating the for loop as soon as a rejection is noticed.
The cost of an enumeration is O(k) rather than O(1) because you compute the sum of the sequence arguments for each enumeration (often twice). That produces an additional factor of k. You could easily eliminate this cost by passing the current sum into the recursive call (which would also eliminate the multiple evaluations). It is trickier to avoid the O(k) cost of copying the sequence into the output list, but that can be done using a better (structure-sharing) data-structure.
The question in your title (as opposed to the problem solved by the code in the body of your question) does actually require enumerating all possible subsets of {1…n}, in which case the number of possible sequences would be exactly 2n.
If you want to solve this recursively, you should use a different pattern that allows caching of previous values, like the one used when calculating Fibonacci numbers. The code for Fibonacci function is basically about the same as what do you seek, it adds previous and pred-previous numbers by index and returns the output as current number. You can use the same technique in your recursive function , but add not f(k-1) and f(k-2), but gather sum of f(k-steps[i]). Something like this (I don't have a Java syntax checker, so bear with syntax errors please):
static List<Integer> cache = new ArrayList<Integer>;
static List<Integer> storedSteps=null; // if used with same value of steps, don't clear cache
public static Integer problem1(Integer numSteps, List<Integer> steps) {
if (!ArrayList::equal(steps, storedSteps)) { // check equality data wise, not link wise
storedSteps=steps; // or copy with whatever method there is
cache.clear(); // remove all data - now invalid
// TODO make cache+storedSteps a single structure
}
return problem1_rec(numSteps,steps);
}
private static Integer problem1_rec(Integer numSteps, List<Integer> steps) {
if (0>numSteps) { return 0; }
if (0==numSteps) { return 1; }
if (cache.length()>=numSteps+1) { return cache[numSteps] } // cache hit
Integer acc=0;
for (Integer i : steps) { acc+=problem1_rec(numSteps-i,steps); }
cache[numSteps]=acc; // cache miss. Make sure ArrayList supports inserting by index, otherwise use correct type
return acc;
}

Allocating N tonnes of food in K rooms with M capacity

I found this problem online:
You have N tonnes of food and K rooms to store them into. Every room has a capacity of M. In how many ways can you distribute the food in the rooms, so that every room has at least 1 ton of food.
My approach was to recursively find all possible variations that satisfy the conditions of the problem. I start with an array of size K, initialized to 1. Then I keep adding 1 to every element of the array and recursively check whether the new array satisfies the condition. However, the recursion tree gets too large too quickly and the program takes too long for slightly higher values of N, K and M.
What would be a more efficient algorithm to achieve this task? Are there any optimizations to be done to the existing algorithm implementation?
This is my implementation:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
public class Main {
// keeping track of valid variations, disregarding duplicates
public static HashSet<String> solutions = new HashSet<>();
// calculating sum of each variation
public static int sum(int[] array) {
int sum = 0;
for (int i : array) {
sum += i;
}
return sum;
}
public static void distributionsRecursive(int food, int rooms, int roomCapacity, int[] variation, int sum) {
// if all food has been allocated
if (sum == food) {
// add solution to solutions
solutions.add(Arrays.toString(variation));
return;
}
// keep adding 1 to every index in current variation
for (int i = 0; i < rooms; i++) {
// create new array for every recursive call
int[] tempVariation = Arrays.copyOf(variation, variation.length);
// if element is equal to room capacity, can't add any more in it
if (tempVariation[i] == roomCapacity) {
continue;
} else {
tempVariation[i]++;
sum = sum(tempVariation);
// recursively call function on new variation
distributionsRecursive(food, rooms, roomCapacity, tempVariation, sum);
}
}
return;
}
public static int possibleDistributions(int food, int rooms, int roomCapacity) {
int[] variation = new int[rooms];
// start from all 1, keep going till all food is allocated
Arrays.fill(variation, 1);
distributionsRecursive(food, rooms, roomCapacity, variation, rooms);
return solutions.size();
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int food = in.nextInt();
int rooms = in.nextInt();
int roomCapacity = in.nextInt();
int total = possibleDistributions(food, rooms, roomCapacity);
System.out.println(total);
in.close();
}
}
Yes, your recursion tree will become large if you do this in a naive manner. Let's say you have 10 tonnes and 3 rooms, and M=2. One valid arrangement is [2,3,5]. But you also have [2,5,3], [3,2,5], [3,5,2], [5,2,3], and [5,3,2]. So for every valid grouping of numbers, there are actually K! permutations.
A possibly better way to approach this problem would be to determine how many ways you can make K numbers (minimum M and maximum N) add up to N. Start by making the first number as large as possible, which would be N-(M*(K-1)). In my example, that would be:
10 - 2*(3-1) = 6
Giving the answer [6,2,2].
You can then build an algorithm to adjust the numbers to come up with valid combinations by "moving" values from left to right. In my example, you'd have:
6,2,2
5,3,2
4,4,2
4,3,3
You avoid the seemingly infinite recursion by ensuring that values are decreasing from left to right. For example, in the above you'd never have [3,4,3].
If you really want all valid arrangements, you can generate the permutations for each of the above combinations. I suspect that's not necessary, though.
I think that should be enough to get you started towards a good solution.
One solution would be to compute the result for k rooms from the result for k - 1 rooms.
I've simplified the problem a bit in allowing to store 0 tonnes in a room. If we have to store at least 1 we can just subtract this in advance and reduce the capacity of rooms by 1.
So we define a function calc: (Int,Int) => List[Int] that computes for a number of rooms and a capacity a list of numbers of combinations. The first entry contains the number of combinations we get for storing 0 , the next entry when storing 1 and so on.
We can easily compute this function for one room. So calc(1,m) gives us a list of ones up to the mth element and then it only contains zeros.
For a larger k we can define this function recursively. We just calculate calc(k - 1, m) and then build the new list by summing up prefixes of the old list. E.g. if we want to store 5 tons, we can store all 5 in the first room and 0 in the following rooms, or 4 in the first and 1 in the following and so on. So we have to sum up the combinations for 0 to 5 for the rest of the rooms.
As we have a maximal capacity we might have to leave out some of the combinations, i.e. if the room only has capacity 3 we must not count the combinations for storing 0 and 1 tons in the rest of the rooms.
I've implemented this approach in Scala. I've used streams (i.e. infinite Lists) but as you know the maximal amount of elements you need this is not necessary.
The time complexity of the approach should be O(k*n^2)
def calc(rooms: Int, capacity: Int): Stream[Long] =
if(rooms == 1) {
Stream.from(0).map(x => if(x <= capacity) 1L else 0L)
} else {
val rest = calc(rooms - 1, capacity)
Stream.from(0).map(x => rest.take(x+1).drop(Math.max(0,x - capacity)).sum)
}
You can try it here:
http://goo.gl/tVgflI
(I've replaced the Long by BigInt there to make it work for larger numbers)
First tip, remove distributionsRecursive and don't build up a list of solutions. The list of all solutions is a huge data set. Just produce a count.
That will let you turn possibleDistributions into a recursive function defined in terms of itself. The recursive step will be, possibleDistributions(food, rooms, roomCapacity) = sum from i = 1 to roomCapacity of possibleDistributions(food - i, rooms - 1, roomCapacity).
You will save a lot of memory, but still have your underlying performance problem. However with a pure recursive function you can now fix that with https://en.wikipedia.org/wiki/Memoization.

How do I go about figuring out this complicated recursion algorithm?

I just started Data Structures and Algorithms which is taught in Java. So far I've only learned C++ in my life so I'm still VERY new to using java.
Anyways I have a homework problem I'm a little stuck on:
Write a recursive method that returns the number of 1's in the binary representation of N. Use the fact that this is equal to the number of 1's in the representation of N/2 + 1, if N is odd.
Now i'm not sure how exactly to do this. I already have a function set up that takes an integer and converts it to binary and stores it in a string, yet the rest I'm kinda lost on.
If I can get some guidance, that would really help.
This is what I have so far:
import java.io.*;
public class Homework1Code {
static void prtbinary(String Molly, int size){
if(size <=0){
return;
}
}
public static void main(String[] args) {
int i = 38;
String binstr = Integer.toBinaryString(i);
System.out.println("The Original Decimal Number is: " + binstr);
prtbinary(binstr, binstr.length());
}
}
Thanks
This is not a hard problem to solve. What you need to do is stop writing code and first solve the problem on paper. Then convert your algorithm to code.
Step one: think!
It is very hard to write a recursive method whose return type is void.
The question is about doing arithmetic, so leave the value as an int rather than convering to a string.
Then there are two facts (for non-negative numbers):
if N is odd then the number of ones is the same as in N/2 plus the one remainder;
if N is even then the number of ones is the same as in N/2.
bitCount of 010101 is bitCount of 010101/2 = 01010 plus 1
bitCount of 010100 is bitCount of 010100/2 = 01010
Rinse and repeat until finished (induction).
Just don't look at the source to Integer.bitCount.
first, reduce the problem to the easiest case ...

Categories