Euler Project Help (Problem 12) - Prime Factors and the like - java

I hate to have to ask, but I'm pretty stuck here.
I need to test a sequence of numbers to find the first which has over 500 factors:
http://projecteuler.net/index.php?section=problems&id=12
-At first I attempted to brute force the answer (finding a number with 480 after a LONG time)
-I am now looking at determining the prime factors of a number and then use them to find all other factors.
I am currently at the stage where I can get an array of prime factors for any number I input - i.e 300 has the prime factors 2 2 3 5 5
Using this array of prime factors I need to be able to calculate the remaining factors - This is the part I am stuck on. Basically, as I understand it, I need to calculate ALL possible combinations of the numbers in the array...
i.e
2 * 2
2 * 2 * 3
2 * 2 * 3 * 5
2 * 3
2 * 3 * 3
...and so forth - But where it gets interesting is with things like...
2 * 5
2 * 3 * 5
...i.e Numbers which are not adjacent to each other in the array
I can't think of a way to code this in a generic fashion for any length array...
I need help! P.S - I am working in Java
EDIT: My brute force code - As it has been suggested brute forcing the problem will work and so there may be an error in my code :(
package euler.problem12;
public class Solution {
public static void main(String[] args) {
int next = 1;
int triangle = 0;
int maxFactors = 0;
while(true) {
triangle = triangle + next;
int factors = 1;
int max = (int) triangle / 2;
for(int i = 1; i <= max; ++i) {
if(triangle % i == 0) {
factors ++;
}
}
if(factors > maxFactors) {
maxFactors = factors;
System.out.println(triangle + "\t" + factors);
}
next++;
}
}
}

OK, second attempt as I was making things far too difficult.
Answer is given here: Link
If you factor a number into its prime
power factors, then the total number
of factors is found by adding one to
all the exponents and multiplying
those results together. Example: 108 =
2^2 * 3^3, so the total number of
factors is (2+1) * (3+1) = 3 * 4 = 12.
Sure enough, the factors of 108 are 1,
2, 3, 4, 6, 9, 12, 18, 27, 36, 54, and
108. This happens because to be a factor, a number must have the same
primes, and raised to the same or lower powers.
So if you know the prime factors, you just need to count the repeated ones and use the above calculation to work out the number of factors.

As far as I can tell, question 12 doesn't mention anything about prime numbers? Is this the one you're looking at?
The sequence of triangle numbers is generated by adding the natural numbers...
If so, then perhaps not thinking about primes will help? ;)

Possibly 3 months too late, but here goes...
I see that answer two has privided the function to give you the answer you require, but in answer to your original question on how you generate all the factors assuming you need to for some reason, then here's how you do it:
Assuming that you have the factors in an array:
int[] primeFactors = new int[] {2, 2, 3, 5, 5};
What you need to do is recurse every in-order permutation for each possible depth, and then reduce the resulting result set to just the unique values.
I'll explain what I mean:
"In-order permutation": assuming you start at position 0 of the array, the next element must be 1, 2, 3 or 4, if you start from 1 then the next one must be 2, 3 or 4 and so on.
"Each possible depth": each single factor, then any two factors, then any three factors and so on until you get to all five factors.
"Reduce the set": If you take two elements, say 0&3, 0&4, 1&3 or 1&4 they all give you 2 * 5 = 10, they all provide the factor 10, so you need to winnow your set to just distinct values. (Phew, this is getting longer than I expected... :))
The way to do this is to use two methods, one to select the maximum depth of recursion, kick off the recustion and the winnow the final results, and the other to recurse the values:
public static void main(String[] args) {
int[] primeFactors = new int[] {2, 2, 3, 5, 5};
List<Integer> allFactors = getAllFactors(primeFactors);
for (int factor : allFactors) {
System.out.println("Factor: " + factor);
}
}
private static List<Integer> getAllFactors(int[] primeFactors) {
Set<Integer> distinctFactors = new HashSet<Integer>();
for (int maxDepth = 0; maxDepth <= primeFactors.length; maxDepth++) {
permutatPrimeFactors(0, maxDepth, 0, 1, primeFactors, distinctFactors);
}
List<Integer> result = new ArrayList<Integer>(distinctFactors);
Collections.sort(result);
return result;
}
private static void permutatPrimeFactors(int depth, int maxDepth, int minIndex, int valueSoFar, int[] primeFactors, Set<Integer> distinctFactors) {
if (depth == maxDepth) {
distinctFactors.add(valueSoFar);
return;
}
for (int index = minIndex; index < primeFactors.length; index++) {
permutatPrimeFactors(depth + 1, maxDepth, index + 1, valueSoFar * primeFactors[index], primeFactors, distinctFactors);
}
}
The getAllFactors uses a Set to make sure we only get distinct values, than adds them to a list and sorts that so that we can display the factors in order.
While permutatPrimeFactors, generates from zero terms (factor = 1) though to all terms (factor = 1 * 2 * 2 *3 * 5 * 5 = 300).
Hope that helps.

Related

Collect Max Coins From An Array In 2 Consecutive Intervals

Given an array A consisting of N integers denoting the number of coins on each box in
the row, and integers K and L denoting, respectively, the number of boxes that robo1 and robo2 can
choose when collecting, returns the maximum number of coins that can be collected by them, or -1
if there are no such intervals.
For example, given A = [6, 1, 4, 6, 3, 2, 7, 4], K = 3, L = 2, your
function should return 24, because robo1 can choose boxes 3 to 5 and
collect 4 + 6 + 3 = 13 coins, and robo2 can choose boxes 7 to 8 and
collect 7 +4 = 11 coins. Thus, they will collect 13 + 11 = 24 coins
in total, and that is the maximum number that can be achieved.
Given A = [10, 19, 15], K = 2, L = 2, your function should return -1,
because it is not possible for robo1 and robo2 to choose two disjoint
intervals.
I have written below function to collect max coins.
public static int getMaxCoins(int[] A, int K, int L) {
if(A.length<K+L)
return -1;
int highest = 0;
int lowest = 0;
if(K>L){
highest = K;
lowest = L;
}
int robo1Coins = 0;
int remainingArray[] = null;
int part1[];
int part2[];
int robo2Coins = 0;
for(int i=0;i+highest<=A.length;i++){
int[] sub = Arrays.copyOfRange(A, i, i+highest);
int count = IntStream.of(sub).sum();
if(count>robo1Coins) {
robo1Coins = count;
part1 = Arrays.copyOfRange(A, 0, i);
part2 = Arrays.copyOfRange(A, i+highest, A.length);
remainingArray = IntStream.concat(Arrays.stream(part1), Arrays.stream(part2)).toArray();
}
}
for(int i=0;i+lowest<=remainingArray.length;i++){
int[] sub = Arrays.copyOfRange(remainingArray, i, i+lowest);
int count = IntStream.of(sub).sum();
if(count>robo2Coins) {
robo2Coins = count;
}
}
System.out.println("Robo1 Coins - "+robo1Coins+" Robo2 Coins-"+robo2Coins);
return robo1Coins+robo2Coins;
}
The above solution is working fine for the given cases.
But I feel my solution has few problems
Not optimistic/Less performant
Failing on edge cases
Not following any algorithmic approach
Please help to point out. What is the right approaches/algorithms available to solve this in more efficient manner.
You can solve the problem with a sliding window algorithm. The window's length should be K+L. Imagine robo1 leading, and robo2 following behind as they march across the array.
As the window moves you need to update separate sums for each robot: sum1 and sum2. You also need to keep track of the best sum seen by the trailing robot: best2, and the best combined sum: bestCombined.
After each window move, update the best results:
best2=max(best2, sum2)
bestCombined=max(bestCombined, best2+sum1)
When the sliding window reaches the end of the array, bestCombined is one of two possible answers. Swap the robots, and run the algorithm again to find the other possible answer.
Here's a sample run of the algorithm.
First with robo1 leading (blue) and robo2 following (red):
Then with robo2 leading, and robo1 following:
The best combined score is 24 which is achieved with robo2 leading.

How to Make a List of Numbers that Sum to n(n-1)/2 [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
I need to come up with an array of n integers, ranging from 0 to n-1 such that the sum of all of them is n(n-1)/2. How should I do this?
One way that I tried doing it was I randomly picked the first n-1 numbers and then picked the last number in a way such that the sum was n(n-1)/2. If it was in the interval [0, n-1], then I was good. Otherwise, I would recursively just run the same function again. However, when I ran this, I got a StackOverflow Error because the recursion ran too many times (none of the lists I made worked).
Is there a better way to randomly generate such lists in Java?
Try the integers from 0 to n-1. Let n = 6
0 1 2 3 4 5
n(n-1)/2 = 6(6-1)/2 = 6(5)/2 = 15
The trivial solution is to create list 0 through n - 1. (The sum of 0 through n - 1 is n(n - 1) / 2.)
If you want a randomized list, take the above list and shuffle it.
If you want a randomized list that isn't simply a permutation of the list 0 through n - 1:
Start with the above list 0 through n - 1
Shuffle the list.
Repeatedly (until you have reached the required level of randomness) do the following:
randomly select two existing list elements: a and b
generate a random number r such that a + r < n and b - r >= 0
a' <- a + r
b' <- b - r
This can be done iteratively in O(n) operations ... depending on how random you need the result to be.
(I'm not sure how many times you need to repeat step 3 to get "sufficient" randomness, but I think it should be O(n) times.)
One Solution:
import java.lang.Math;
...
public int[] solution(int n) {
int[] solution = new int[n];
int targetSum = (n * (n - 1)) / 2;
int runningSum = 0;
double avgRemainder = 0.0;
for (int i = 0; i < n - 1; i++) {
do {
solution[i] = (int)(Math.random() * n);
avgRemainder = (targetSum - runningSum - solution[i])/(n - (i + 1));
if (avgRemainder >= 0.0 && avgRemainder <= (n - 1)) {
runningSum += solution[i];
}
} while (!(avgRemainder >= 0.0 && avgRemainder <= (n - 1)));
}
solution[n - 1] = targetSum - runningSum;
return solution;
}
This will generate a random number, but before adding it to the list of solutions, it will check to see if it will cause the remaining slots to average outside of the range of acceptable numbers, which includes overshooting the target sum.
The cons to this (particularly if order matters) is that it will cause funneling at the end, if you randomly generate large numbers at the beginning, then obviously the remaining numbers will loop until they are small enough to fit in the solution... for example:
If n = 5
If we randomly generate the first two numbers to be 4
[4, 4, ?, ?, ?]
Then this method will loop the 3rd random number until it is between 0 and 2, and if it is 2...
[4, 4, 2, ?, ?]
Then it will loop the remaining numbers until they are 0.
[4, 4, 2, 0, 0]
This should be fine with larger values of n, and it is iterative instead of recursive.
EDIT:
So actually the very last item must be forced because there will only be one solution for solution[n-1]. I fixed the code above to add that because it was getting an: Exception in thread "main" java.lang.ArithmeticException: / by zero.

Meaning of the formula how to find lost element in array?

The task is to find lost element in the array. I understand the logic of the solution but I don't understand how does this formula works?
Here is the solution
int[] array = new int[]{4,1,2,3,5,8,6};
int size = array.length;
int result = (size + 1) * (size + 2)/2;
for (int i : array){
result -= i;
}
But why we add 1 to total size and multiply it to total size + 2 /2 ?? In all resources, people just use that formula but nobody explains how that formula works
The sum of the digits 1 thru n is equal to ((n)(n+1))/2.
e.g. for 1,2,3,4,5 5*6/2 = 15.
But this is just a quick way to add up the numbers from 1 to n. Here is what is really going on.
The series computes the sum of 1 to n assuming they all were present. But by subtracting each number from that sum, the remainder is the missing number.
The formula for an arithmetic series of integers from k to n where adjacent elements differ by 1 is.
S[k,n] = (n-k+1)(n+k)/2
Example: k = 5, n = 10
S[k,n] = 5 6 7 8 9 10
S[k,n] = 10 9 8 7 6 5
S[k,n] = (10-5+1)*(10+5)/2
2S[k,n] = 6 * 15 / 2
S[k,n] = 90 / 2 = 45
For any single number missing from the sequence, by subtracting the others from the sum of 45, the remainder will be the missing number.
Let's say you currently have n elements in your array. You know that one element is missing, which means that the actual size of your array should be n + 1.
Now, you just need to calculate the sum 1 + 2 + ... + n + (n+1).
A handy formula for computing the sum of all integers from 1 up to k is given by k(k+1)/2.
By just replacing k with n+1, you get the formula (n+1)(n+2)/2.
It's simple mathematics.
Sum of first n natural numbers = n*(n+1)/2.
Number of elements in array = size of array.
So, in this case n = size + 1
So, after finding the sum, we are subtracting all the numbers from array individually and we are left with the missing number.
Broken sequence vs full sequence
But why we add 1 to total size and multiply it to total size + 2 /2 ?
The amount of numbers stored in your array is one less than the maximal number, as the sequence is missing one element.
Check your example:
4, 1, 2, 3, 5, 8, 6
The sequence is supposed to go from 1 to 8, but the amount of elements (size) is 7, not 8. Because the 7 is missing from the sequence.
Another example:
1, 2, 3, 5, 6, 7
This sequence is missing the 4. The full sequence would have a length of 7 but the above array would have a length of 6 only, one less.
You have to account for that and counter it.
Sum formula
Knowing that, the sum of all natural numbers from 1 up to n, so 1 + 2 + 3 + ... + n can also be directly computed by
n * (n + 1) / 2
See the very first paragraph in Wikipedia#Summation.
But n is supposed to be 8 (length of the full sequence) in your example, not 7 (broken sequence). So you have to add 1 to all the n in the formula, receiving
(n + 1) * (n + 2) / 2
I guess this would be similar to Missing Number of LeetCode (268):
Java
class Solution {
public static int missingNumber(int[] nums) {
int missing = nums.length;
for (int index = 0; index < nums.length; index++)
missing += index - nums[index];
return missing;
}
}
C++ using Bit Manipulation
class Solution {
public:
int missingNumber(vector<int> &nums) {
int missing = nums.size();
int index = 0;
for (int num : nums) {
missing = missing ^ num ^ index;
index++;
}
return missing;
}
};
Python I
class Solution:
def missingNumber(self, nums):
return (len(nums) * (-~len(nums))) // 2 - sum(nums)
Python II
class Solution:
def missingNumber(self, nums):
return (len(nums) * ((-~len(nums))) >> 1) - sum(nums)
Reference to how it works:
The methods have been explained in the following links:
Missing Number Discussion
Missing Number Solution

How to calculate Big O of Dynamic programming (Memoization) algorithm

How would I go about calculating the big O of a DP algorithm. I've come to realize my methods for calculating algorithms doesn't always work. I would use simple tricks to extract what the Big O was. For example if I were evaluating the none memoized version of the algorithm below (removing the cache mechanism) I would look at the number of times the recursive method called itself in this case 3 times. I would then raise this value to n giving O(3^n). With DP that isn't right at all because the recursive stack doesn't go as deep. My intuition tells me that the Big O of the DP solution would be O(n^3). How would we verbally explain how we came up with this answer. More importantly what is a technique that can be used to find the Big O of similar problems. Since it is DP I'm sure the number of sub problems is important how do we calculate the number of sub problems.
public class StairCase {
public int getPossibleStepCombination(int n) {
Integer[] memo = new Integer[n+1];
return getNumOfStepCombos(n, memo);
}
private int getNumOfStepCombos(int n, Integer[] memo) {
if(n < 0) return 0;
if(n == 0) return 1;
if(memo[n] != null) return memo[n];
memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
return memo[n];
}
}
The first 3 lines do nothing but compare int values, access an array by index, and see if an Integer reference is null. Those things are all O(1), so the only question is how many times the method is called recursively.
This question is very complicated, so I usually cheat. I just use a counter to see what's going on. (I've made your methods static for this, but in general you should avoid static mutable state wherever possible).
static int counter = 0;
public static int getPossibleStepCombination(int n) {
Integer[] memo = new Integer[n+1];
return getNumOfStepCombos(n, memo);
}
private static int getNumOfStepCombos(int n, Integer[] memo) {
counter++;
if(n < 0) return 0;
if(n == 0) return 1;
if(memo[n] != null) return memo[n];
memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
return memo[n];
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
counter = 0;
getPossibleStepCombination(i);
System.out.print(i + " => " + counter + ", ");
}
}
This program prints
0 => 1, 1 => 4, 2 => 7, 3 => 10, 4 => 13, 5 => 16, 6 => 19, 7 => 22, 8 => 25, 9 => 28,
so it looks like the final counter values are given by 3n + 1.
In a more complicated example, I might not be able to spot the pattern, so I enter the first few numbers (e.g. 1, 4, 7, 10, 13, 16) into the Online Encyclopedia of Integer Sequences and I usually get taken to a page containing a simple formula for the pattern.
Once you've cheated in this way to find out the rule, you can set about understanding why the rule works.
Here's how I understand where 3n + 1 comes from. For each value of n you only have to do the line
memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
exactly once. This is because we are recording the results and only doing this line if the answer has not already been calculated.
Therefore, when we start with n == 5 we run that line exacly 5 times; once for n == 5, once with n == 4, once with n == 3, once with n == 2 and once with n == 1. So that's 3 * 5 == 15 times the method getNumOfStepCombos gets called from itself. The method also gets called once from outside itself (from getPossibleStepCombination), so the total number of calls is 3n + 1.
Therefore this is an O(n) algorithm.
If an algorithm has lines that are not O(1) this counter method cannot be used directly, but you can often adapt the approach.
Paul's answer is technically not wrong but is a bit misleading. We should be calculating big O notation by how the function responds to changes in input size. Paul's answer of O(n) makes the complexity appear to be linear time when it really is exponential to the number of bits required to represent the number n. So for example, n=10 has ~30 calculations and m=2 bits. n=100 has ~300 calculations and m=3 bits. n=1000 has ~3000 calculations and m=4 bits.
I believe that your function's complexity would be O(2^m) where m is number of bits needed to represent n. I referred to https://www.quora.com/Why-is-the-Knapsack-problem-NP-complete-even-when-it-has-complexity-O-nW for a lot of my answer.

Performance when searching for missing numbers in array

Given is a list containing all but 2 numbers between 1-20 (randomly ordered).
I need to find those 2 numbers.
This is the (working) program I came up with:
public static void main(String[] args) {
int[] x= {1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
ArrayList al= new ArrayList();
Map map= new HashMap();
for(int i=0;i<x.length;i++)
{
map.put(x[i], x[i]);
}
for(int i=1;i<=20;i++)
{
if(map.get(i)==null)
al.add(i);
}
for(int i=0;i<al.size();i++)
{
System.out.println(al.get(i));
}
}
I would like to know if the program is good from a performance point of view (memory and bigO(n))?
You don't need a map. Just an additional boolean array with size 20.
for (int i = 0; i < input.length; i++)
arr[input[i]] = true;
for (int i = 1; i <= 20; i++)
if (arr[i] == false) {
//number `i` is missing
}
Now I will expose a straightforward math solution.
First sum all numbers in the array. For example you have 5, 1, 4 for the numbers from 1, 2, 3, 4, 5. So 2 and 3 are missing. We can find them easily with math.
5 + 1 + 4 = 10
1 + 2 + 3 + 4 + 5 = 15
So we know x + y = 15 - 10 = 5
Now we will get a second equation:
1 * 4 * 5 = 20
1 * 2 * 3 * 4 * 5 = 120
=> x * y = 120 / 20 = 6
So:
x + y = 5
x * y = 6
=> x = 2, y = 3 or x = 3, y = 2 which is the same.
So x = 2, y = 3
Another option would be to use a BitSet where each bit is set for the corresponding number in the array.
Your code runs at O(n) due to the map.put operation. The for loop below that will run at O(n) at the worst case too, so in total, your whole function runs at O(n).
You can optimise your code further. For example, you are using additional memory. To improve on this, you need to come up with 2 eqns to deduce missing numbers x and y.
Eqn1:
Summation(1 till 20) = n*(n+1)/2
Add all numbers in array and store in temp.
x+y = n*(n+1)/2 - temp
Eqn2:
Multiply(1 till 20) = n!
Multiply all numbers in array and store in temp.
x*y = temp / n!
Solve the equations to get x and y.
So this will run O(n) without much memory.
It should not be anything worse than linear time O(n): one run to populate a flag array, and a second run to check the flag array.

Categories