Related
You are given two strings S and T. An infinitely long string is formed in the following manner:
Take an empty string,
Append S one time,
Append T two times,
Append S three times,
Append T four times,
and so on, appending the strings alternately and increasing the number of repetitions by 1 each time.
You will also be given an integer K.
You need to tell the Kth Character of this infinitely long string.
Sample Input (S, T, K):
a
bc
4
Sample Output:
b
Sample Explanation:
The string formed will be "abcbcaaabcbcbcbcaaaaa...". So the 4th character is "b".
My attempt:
public class FindKthCharacter {
public char find(String S, String T, int K) {
// lengths of S and T
int s = S.length();
int t = T.length();
// Counters for S and T
int sCounter = 1;
int tCounter = 2;
// To store final chunks of string
StringBuilder sb = new StringBuilder();
// Loop until K is greater than zero
while (K > 0) {
if (K > sCounter * s) {
K -= sCounter * s;
sCounter += 2;
if (K > tCounter * t) {
K -= tCounter * t;
tCounter += 2;
} else {
return sb.append(T.repeat(tCounter)).charAt(K - 1);
}
} else {
return sb.append(S.repeat(sCounter)).charAt(K - 1);
}
}
return '\u0000';
}
}
But is there any better way to reduce its time complexity?
I've tried to give a guide here, rather than just give the solution.
If s and t are the lengths of the strings S and T, then you need to find the largest odd n such that
(1+3+5+...+n)s + (2+4+6+...+(n+1))t < K.
You can simplify these expressions to get a quadratic equation in n.
Let N be (1+3+..+n)s + (2+4+6+...+(n+1))t. You know that K will lie either in the next (n+2) copies of S, or the (n+3) copies of T that follow. Compare K to N+(n+2)s, and take the appropriate letter of either S or T using a modulo.
The only difficult step here is solving the large quadratic, but you can do it in O(log K) arithmetic operations easily enough by doubling n until it's too large, and then using a binary search on the remaining range. (If K is not too large so that floating point is viable, you can do it in O(1) time using the well-known quadratic formula).
Here my quick attempt, there probably is a better solution. Runtime is still O(sqrt n), but memory is O(1).
public static char find(String a, String b, int k) {
int lenA = a.length();
int lenB = b.length();
int rep = 0;
boolean isA = false;
while (k >= 0) {
++rep;
isA = !isA;
k -= (isA ? lenA : lenB) * rep;
}
int len = (isA ? lenA : lenB);
int idx = (len * rep + k) % len;
return (isA ? a : b).charAt(idx);
}
Here's a O(1) solution that took me some time to come up with (read I would have failed an interview on time). Hopefully the process is clear and you can implement it in code.
Our Goal is to return the char that maps to the kth index.
But How? Just 4 easy steps, actually.
Step 1: Find out how many iterations of our two patterns it would take to represent at least k characters.
Step 2: Using this above number of iterations i, return how many characters are present in the previous i-1 iterations.
Step 3: Get the number of characters n into iteration i that our kth character is. (k - result of step 2)
Step 4: Mod n by the length of the pattern to get index into pattern for the specific char. If i is odd, look into s, else look into t.
For step 1, we need to find a formula to give us the iteration i that character k is in. To derive this formula, it may be easier to first derive the formula needed for step 2.
Step 2's formula is basically given an iteration i, return how many characters are present in that iteration. We are solving for 'k' in this equation and are given i, while it's the opposite for step 1 where were are solving for i given k. If we can derive the equation of find k given i, then we can surely reverse it to find i given k.
Now, let's try to derive the formula for step 2 and find k given i. Here it's best to start with the most basic example to see the pattern.
s = "a", t = "b"
i=1 a
i=2 abb
i=3 abbaaa
i=4 abbaaabbbb
i=5 abbaaabbbbaaaaa
i=6 abbaaabbbbaaaaabbbbbb
Counting the total number of combined chars for each pattern during its next iteration gives us:
#iterations of pattern: 1 2 3 4 5 6 7 8 9 10
every new s iteration: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
every new t iteration: 2, 6, 12, 20, 30, 42, 56, 72, 90, 110
You might notice some nice patterns here. For example, s has a really nice formula to find out how many combined characters it has at any given iteration. It's simply (# of s iterations^2)*s.length. t also has a simple formula. It is (# of t iterations * (# of t iterations + 1))*t.length. You may have noticed that these formulas are the formulas for sum of odd and even numbers (if you did you get a kudos). This makes sense because each pattern's sum for an iteration i is the sum of all of its previous iterations.
Using s,t as length of their respective patterns, we now have the following formula to find the total number of chars at a given iteration.
#chars = s*(# of s iterations)^2 + t * (# of t iterations * (# of t iterations + 1))
Now we just need to do some math to get the number of iterations for each pattern given i.
# of s iterations given i = ceil(i/2.0)
# of t iterations given i = floor(i/2) which / operation gives us by default
Plugging these back into our formula we get:
total # of chars = s*(ceil(i/2.0)^2) + t*((i/2)*((i/2)+1))
We have just completed step 2, and we now know at any given iteration how many total chars there are. We could stop here and start picking random iterations and adjusting accordingly until we get near k, but we can do better than that. Let's use the above formula now to complete step 1 which we skipped. We just need to reorganize our equation to solve for i now.
Doing some simplyfying we get:
// 2
// i i i
// s (-) + t - ( - + 1 ) = k
// 2 2 2
// ----------------------------
// 2
// i t i
// s - + - ( - + 1 )i = k
// 4 2 2
// ----------------------------
// 2 2
// si ti ti
// ---- + ---- + ---- - k = 0
// 4 4 2
// ----------------------------
//
// 2 2
// si + ti + 2ti - 4k = 0
// ----------------------------
// 2
// (s + t)i + 2ti - 4k = 0
// ----------------------------
This looks like a polynomial. Wow! You're right! That means we can solve it using the quadratic formula.
A=(s+t), B=2t, C=-4k
quadratic formula = (-2t + sqrt(2t^2 + 16(s+t)k)) / 2(s+t)
This is our formula for step 1, and it will give us the iteration that the kth character is on. We just need to ceil it. I'm actually not smart enough to know why this works. It just does. Here is a desmos graph that graphs our two polynomials from step 2: s(Siterations)^2 and t(Titerations (Titerations + 1)).
The area under both curves is our total number of chars at an iteration (the vertical line). The formula from step 1 is also graphed, and we can see that for any s, t, k that the x intercept (which represents our xth iteration) is always: previous iteration < x <= current iteration, which is why the ceil works.
We have now completed steps 1 and 2. We have a formula to get the ith iteration that the kth character is on and a formula that gives us how many characters are in an ith iteration. Steps 3 and 4 should follow and we get our answer. This is constant time.
How do you find abrupt change in an array? For example, if you have following array:
1,3,8,14,58,62,69
In this case, there is a jump from 14 to 58
OR
79,77,68,61,9,3,1
In this case, there is a drop from 61 to 9
In both examples, there are small and big jumps. For example, in 2nd case, there is a small drop from 77 to 68. However, this must be ignored if a larger jump/drop is found. I have following algorithm in my mind but I am not sure if this will cover all possible cases:
ALGO
Iterate over array
Diff (i+1)-i
store first difference in a variable
if next diff is bigger than previous then overwrite
For the following example, this algo will not work for the following case:
1, 2, 4, 6, 34, 38, 41, 67, 69, 71
There are two jumps in this array. So it should be arranged like
[1, 2, 4, 6], [34, 38, 41], [67, 69, 71]
In the end, this is pure statistics. You have a data set; and you are look for a certain forms of outliers. In that sense, your requirement to detect "abrupt changes" is not very precise.
I think you should step back here; and have a deeper look into the mathematics behind your problem - to come up with clear "semantics" and crisp definitions for your actual problem (for example based on average, deviation, etc.). The wikipedia link I gave above should be a good starting point for that part.
From there on, to get to an Java implementation, you might start looking here.
I would look into using a Moving Average, this involves looking at an average for the last X ammount of values. Do this based on the change in value (Y1 - Y2). Any large deviations from the average could be seen as a big shift.
However given how small your datasets are a moving average would likely yeild bad results. With such a small sample size it might be better to take an average of all values in the array instead:
double [] nums = new double[] {79,77,68,61,9,3,1};
double [] deltas = new double[nums.length-1];
double advDelta = 0;
for(int i=0;i<nums.length-1;i++) {
deltas[i] = nums[i+1]-nums[i];
advDelta += deltas[i] / deltas.length;
}
// search for deltas > average
for(int i=0;i<deltas.length;i++) {
if(Math.abs(deltas[i]) > Math.abs(advDelta)) {
System.out.println("Big jump between " + nums[i] + " " + nums[i+1]);
}
}
This problem doesn't have an absolute solution, you'll have to determine thresholds for the context in which the solution is to be applied.
No algorithm can give us the rule for the jump. We as humans are able to determine these changes because we are able to see the entire data at one glance for now. But if data set is large enough then it would be difficult for us to say which jumps are to be considered. For example if on average differences between consecutive numbers are 10 then any difference above that would be considered a jump. However in a large data set there could be differences which are sort of spikes or which start a new normal difference like from 10 to differences suddenly become 100. We will have to decide if we want to get the jumps based on the difference average 10 or 100.
If we are interested in local spike only then it's possible to use moving average as suggested by #ug_
However moving average has to be moving, meaning we maintain a set of local numbers with a fixed set size. On that we calculate the average of the differences and then compare them to the local differences.
However here also we again face the problem to determine the size of the local set. This threshold determines the granularity of the jumps that we capture. A very large set will tend to ignore the closer jumps and a smaller one will tend to provide false positives.
Following a simple solution where you can try setting the thresholds. Local set size in this case is 3, that's the minimum that can be used as it will give us minimum count of differences required that is 2.
public class TestJump {
public static void main(String[] args) {
int[] arr = {1, 2, 4, 6, 34, 38, 41, 67, 69, 71};
//int[] arr = {1,4,8,13,19,39,60,84,109};
double thresholdDeviation = 50; //percent jump to detect, set for your reuirement
double thresholdDiff = 3; //Minimum difference between consecutive differences to avoid false positives like 1,2,4
System.out.println("Started");
for(int i = 1; i < arr.length - 1; i++) {
double diffPrev = Math.abs(arr[i] - arr[i-1]);
double diffNext = Math.abs(arr[i+1] - arr[i]);
double deviation = Math.abs(diffNext - diffPrev) / diffPrev * 100;
if(deviation > thresholdDeviation && Math.abs(diffNext - diffPrev) > thresholdDiff) {
System.out.printf("Abrupt change # %d: (%d, %d, %d)%n", i, arr[i-1], arr[i], arr[i+1]);
i++;
}
//System.out.println(deviation + " : " + Math.abs(diffNext - diffPrev));
}
System.out.println("Finished");
}
}
Output
Started
Abrupt change # 3: (4, 6, 34)
Abrupt change # 6: (38, 41, 67)
Finished
If you're trying to solve a larger problem than just arrays like finding spikes in medical data or images, then you should checkout neural networks.
I've been struggle with question I'm trying to solve as part of test preparation, and I thought I could use your help.
I need to write a Boolean method that takes array with integers (positive and negative), and return true if the array can be split to two equals groups, that the amount of every group's numbers is equals to the other group.
For exmaple, for this array:
int[]arr = {-3, 5, 12, 14, -9, 13};
The method will return true, since -3 + 5 + 14 = 12 + -9 + 13.
For this array:
int[]arr = {-3, 5, -12, 14, -9, 13};
The method will return false since even though -3 + 5 + 14 + -12 = -9 + 13, the amount of numbers in every side of the equation isn't equals.
For the array:
int[]arr = {-3, 5, -12, 14, -9};
The method will return false since array length isn't even.
The method must be recursive, overloading is allowed, every assist method must be recursive too, and I don't need to worry about complexity.
I've been trying to solve this for three hours, I don't even have a code to show since all the things I did was far from the solution.
If someone can at least give me some pseudo code it will be great.
Thank you very much!
You asked for pseudocode, but sometimes it's just as easy and clear to write it as Java.
The general idea of this solution is to try adding each number to either the left or the right of the equation. It keeps track of the count and sum on each side at each step in the recursion. More explanation in comments:
class Balance {
public static void main(String[] args) {
System.out.println(balanced(-3, 5, 12, 14, -9, 13)); // true
System.out.println(balanced(-3, 5, -12, 14, -9, 13)); // false
}
private static boolean balanced(int... nums) {
// First check if there are an even number of nums.
return nums.length % 2 == 0
// Now start the recursion:
&& balanced(
0, 0, // Zero numbers on the left, summing to zero.
0, 0, // Zero numbers on the right, summing to zero.
nums);
}
private static boolean balanced(
int leftCount, int leftSum,
int rightCount, int rightSum,
int[] nums) {
int idx = leftCount + rightCount;
if (idx == nums.length) {
// We have attributed all numbers to either side of the equation.
// Now check if there are an equal number and equal sum on the two sides.
return leftCount == rightCount && leftSum == rightSum;
} else {
// We still have numbers to allocate to one side or the other.
return
// What if I were to place nums[idx] on the left of the equation?
balanced(
leftCount + 1, leftSum + nums[idx],
rightCount, rightSum,
nums)
// What if I were to place nums[idx] on the right of the equation?
|| balanced(
leftCount, leftSum,
rightCount + 1, rightSum + nums[idx],
nums);
}
}
}
This is just a first idea solution. It's O(2^n), which is obviously rather slow for large n, but it's fine for the size of problems you have given as examples.
The problem described is a version of the Partition problem. First note that your formulation is equivalent to deciding whether there is a subset of the input which sums up to half of the sum of all elements (which is required to be an integral number, otherwise the instance cannot be solved, but this is easy to check). Basically, in each recursive step, it is to be decided whether the first number is to be selected into the subset or not, resulting in different recursive calls. If n denotes the number of elements, there must be n/2 (which is required to be integral again) items selected.
Let Sum denote the sum of the input and let Target := Sum / 2 which in the sequel is assumed to be integral. if we let
f(arr,a,count) := true
if there is a subset of arr summing up to a with
exactly count elements
false
otherwise
we obtain the following recursion
f(arr,a,count) = (arr[0] == a && count == 1)
||
(a == 0 && count == 0)
if arr contains only one element
f(arr\arr[0], a, count)
||
f(arr\arr[0], a - arr[0], count -1)
if arr contains more than one element
where || denotes logical disjuction, && denoted logical conjunction and \ denotes removal of an element.
The two cases for a non-singleton array correspond to chosing the first element of arr into the desired subset or its relative complement. Note that in an actual implementation, a would not be actually removed from the array; a starting index, which is used as an additional argument, would be initialized with 0 and increased in each recursive call, eventually reaching the end of the array.
Finally, f(arr,Target,n/2) yields the desired value.
Your strategy for this should be to try all combinations possible. I will try to document how I would go about to get to this.
NOTE that I think the requirement: make every function use recursion is a bit hard, because I would solve that by leaving out some helper functions that make the code much more readable, so in this case I wont do it like that.
With recursion you always want to make progression towards a final solution, and detect when you are done. So we need two parts in our function:
The recursive step: for which we will take the first element of the input set, and try what happens if we add it to the first set, and if that doesn't find a solution we'll try what happens when we add it to the second set.
Detect when we are done, that is when the input set is empty, in that case we either have found a solution or we have not.
A trick in our first step is that after taking the first element of our set, if we try to partition the remainder, we don't want the 2 sets being equal anymore, because we already assigned the first element to one of the sets.
This leads to a solution that follows this strategy:
public boolean isValidSet(MySet<int> inputSet, int sizeDifferenceSet1minus2)
{
if (inputSet.isEmpty())
{
return sizeDifferenceSet1minus2== 0;
}
int first = inptuSet.takeFirst();
return isValidSet(inputSet.copyMinusFirst(), sizeDifferenceSet1minus2+ first)
|| isValidSet(inputSet.copyMinusFirst(), sizeDifferenceSet1minus2+ -1 * first);
}
This code requires some help functions that you will still need to implement.
What it does is first test if we have reached the end condition, and if so returns if this partition is successful. If we still have elements left in the set, we try what happens if we add it to the first set and then what happens when adding it to the second set. Note that we don't actually keep track of the sets, we just keep track of the size difference between set 1 minus 2, decreasing the (but instead you could pass along both sets).
Also note that for this implementation to work, you need to make copies of the input set and not modify it!
For some background information: This problem is called the Partition Problem, which is famous for being NP-complete (which means it probably is not possible to solve it efficiently for large amounts of input data, but it is very easy to verify that a partitioning is indeed a solution.
Here is a verbose example:
public static void main(String[] args)
{
System.out.println(balancedPartition(new int[] {-3, 5, 12, 14, -9, 13})); // true
System.out.println(balancedPartition(new int[] {-3, 5, -12, 14, -9, 13})); // false
System.out.println(balancedPartition(new int[] {-3, 5, -12, 14, -9})); // false
}
public static boolean balancedPartition(int[] arr)
{
return balancedPartition(arr, 0, 0, 0, 0, 0, "", "");
}
private static boolean balancedPartition(int[] arr, int i, int groupA, int groupB, int counterA, int counterB, String groupAStr, String groupBStr)
{
if (groupA == groupB && counterA == counterB && i == arr.length) // in case the groups are equal (also in the amount of numbers)
{
System.out.println(groupAStr.substring(0, groupAStr.length() - 3) + " = " + groupBStr.substring(0, groupBStr.length() - 3)); // print the groups
return true;
}
if (i == arr.length) // boundaries checks
return false;
boolean r1 = balancedPartition(arr, i + 1, groupA + arr[i], groupB, counterA + 1, counterB, groupAStr + arr[i] + " + ", groupBStr); // try add to group 1
boolean r2 = balancedPartition(arr, i + 1, groupA, groupB + arr[i], counterA, counterB + 1, groupAStr, groupBStr + arr[i] + " + "); // try add to group 2
return r1 || r2;
}
Output:
-3 + 5 + 14 = 12 + -9 + 13 // one option for the first array
12 + -9 + 13 = -3 + 5 + 14 // another option for the first array
true // for the first array
false // for the second array
false // for the third array
Consider this method:
public static int[] countPairs(int min, int max) {
int lastIndex = primes.size() - 1;
int i = 0;
int howManyPairs[] = new int[(max-min)+1];
for(int outer : primes) {
for(int inner : primes.subList(i, lastIndex)) {
int sum = outer + inner;
if(sum > max)
break;
if(sum >= min && sum <= max)
howManyPairs[sum - min]++;
}
i++;
}
return howManyPairs;
}
As you can see, I have to count how many times each number between min and max can be expressed as a sum of two primes.
primes is an ArrayList with all primes between 2 and 2000000. In this case, min is 1000000 and max is 2000000, that's why primes goes until 2000000.
My method works fine, but the goal here is to do something faster.
My method takes two loops, one inside the other, and it makes my algorithm an O(n²). It sucks like bubblesort.
How can I rewrite my code to accomplish the same result with a better complexity, like O(nlogn)?
One last thing: I'm coding in Java, but your reply can be in also Python, VB.Net, C#, Ruby, C or even just a explanation in English.
For each number x between min and max, we want to compute the number of ways x can be written as the sum of two primes. This number can also be expressed as
sum(prime(n)*prime(x-n) for n in xrange(x+1))
where prime(x) is 1 if x is prime and 0 otherwise. Instead of counting the number of ways that two primes add up to x, we consider all ways two nonnegative integers add up to x, and add 1 to the sum if the two integers are prime.
This isn't a more efficient way to do the computation. However, putting it in this form helps us recognize that the output we want is the discrete convolution of two sequences. Specifically, if p is the infinite sequence such that p[x] == prime(x), then the convolution of p with itself is the sequence such that
convolve(p, p)[x] == sum(p[n]*p[x-n] for n in xrange(x+1))
or, substituting the definition of p,
convolve(p, p)[x] == sum(prime(n)*prime(x-n) for n in xrange(x+1))
In other words, convolving p with itself produces the sequence of numbers we want to compute.
The straightforward way to compute a convolution is pretty much what you were doing, but there are much faster ways. For n-element sequences, a fast Fourier transform-based algorithm can compute the convolution in O(n*log(n)) time instead of O(n**2) time. Unfortunately, this is where my explanation ends. Fast Fourier transforms are kind of hard to explain even when you have proper mathematical notation available, and as my memory of the Cooley-Tukey algorithm isn't as precise as I'd like it to be, I can't really do it justice.
If you want to read more about convolution and Fourier transforms, particularly the Cooley-Tukey FFT algorithm, the Wikipedia articles I've just linked would be a decent start. If you just want to use a faster algorithm, your best bet would be to get a library that does it. In Python, I know scipy.signal.fftconvolve would do the job; in other languages, you could probably find a library pretty quickly through your search engine of choice.
What you´re searching is the count of Goldbach partitions for each number
in your range, and imho there is no efficient algorithm for it.
Uneven numbers have 0, even numbers below 4*10^18 are guaranteed to have more than 0,
but other than that... to start with, if even numbers (bigger than 4*10^18) with 0 partitions exist
is an unsolved problem since 1700-something, and such things as exact numbers are even more complicated.
There are some asymptotic and heuristic solutions, but if you want the exact number,
other than getting more CPU and RAM, there isn´t be much you can do.
The other answers have an outer loop that goes from N to M. It's more efficient, however, for the outer loop (or loops) to be pairs of primes, used to build a list of numbers between N and M that equal their sums.
Since I don't know Java I'll give a solution in Ruby for a specific example. That should allow anyone interested to implement the algorithm in Java, regardless of whether they know Ruby.
I initially assume that two primes whose product equals a number between M and N must be unique. In other words, 4 cannot be express as 4 = 2+2.
Use Ruby's prime number library.
require 'prime'
Assume M and N are 5 and 50.
lower = 5
upper = 50
Compute the prime numbers up to upper-2 #=> 48, the 2 being the first prime number.
primes = Prime.each.take_while { |p| p < upper-2 }
#=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
Construct an enumerator of all combinations of two primes.
enum = primes.combination(2)
=> #<Enumerator: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]:combination(2)>
We can see the elements that will be generated by this enumerator by converting it to an array.
enum.to_a
#=> [[2, 3], [2, 5],..., [2, 47], [3, 5],..., [43, 47]] (105 elements)
Just think of enum as an array.
Now construct a counting hash whose keys are numbers between lower and upper for which there is at least one pair of primes that sum to that number and whose values are the numbers of pairs of primes that sum to the value of the associated key.
enum.each_with_object(Hash.new(0)) do |(x,y),h|
sum = x+y
h[sum] += 1 if (lower..upper).cover?(sum)
end
#=> {5=>1, 7=>1, 9=>1, 13=>1, 15=>1, 19=>1, 21=>1, 25=>1, 31=>1, 33=>1,
# 39=>1, 43=>1, 45=>1, 49=>1, 8=>1, 10=>1, 14=>1, 16=>2, 20=>2, 22=>2,
# 26=>2, 32=>2, 34=>3, 40=>3, 44=>3, 46=>3, 50=>4, 12=>1, 18=>2, 24=>3,
# 28=>2, 36=>4, 42=>4, 48=>5, 30=>3, 38=>1}
This shows, for example, that there are two ways that 16 can be expressed as the sum of two primes (3+13 and 5+11), three ways for 34 (3+31, 5+29 and 11+23) and no way for 6.
If the two primes being summed need not be unique (e.g., 4=2+2 is to be included), only a slight change is needed.
arr = primes.combination(2).to_a.concat(primes.zip(primes))
whose sorted values are
a = arr.sort
#=> [[2, 2], [2, 3], [2, 5], [2, 7],..., [3, 3],..., [5, 5],.., [47, 47]] (120 elements)
then
a.each_with_object(Hash.new(0)) do |(x,y),h|
sum = x+y
h[sum] += 1 if (lower..upper).cover?(sum)
end
#=> {5=>1, 7=>1, 9=>1, 13=>1, 15=>1, 19=>1, 21=>1, 25=>1, 31=>1, 33=>1,
# 39=>1, 43=>1, 45=>1, 49=>1, 6=>1, 8=>1, 10=>2, 14=>2, 16=>2, 20=>2,
# 22=>3, 26=>3, 32=>2, 34=>4, 40=>3, 44=>3, 46=>4, 50=>4, 12=>1, 18=>2,
# 24=>3, 28=>2, 36=>4, 42=>4, 48=>5, 30=>3, 38=>2}
a should be replaced by arr. I used a here merely to order the elements of the resulting hash so that it would be easier to read.
Since I just wanted to describe the approach, I used a brute force method to enumerate the pairs of elements of primes, throwing away 44 of the 120 pairs of primes because their sums fall outside the range 5..50 (a.count { |x,y| !(lower..upper).cover?(x+y) } #=> 44). Clearly, there's considerable room for improvement.
A sum of two primes means N = A + B, where A and B are primes, and A < B, which means A < N / 2 and B > N / 2. Note that they can't be equal to N / 2.
So, your outer loop should only loop from 1 to floor((N - 1) / 2). In integer math, the floor is automatic.
Your inner loop can be eliminated if the primes are stored in a Set. Assuming your array is sorted (fair assumption), use a LinkedHashSet, such that iterating the set in the outer loop can stop at (N - 1) / 2.
I'll leave it up to you to code this.
Update
Sorry, the above is an answer to the problem of finding A and B for a particular N. Your question was to find all N between min and max (inclusive).
If you follow to logic of the above, you should be able to apply that to your problem.
Outer loop should be from 1 to max / 2.
Inner loop should be from min - outer to max - outer.
To find the starting point of the inner loop, you can keep some extra index variables around, or you can rely on your prime array being sorted and use Arrays.binarySearch(primes, min - outer). First option is likely a little bit faster, but second option is definitely simpler.
Problem
In this project you will write a Java program that reads a positive integer n from standard input, then
prints out the first n prime numbers. We say that an integer m is divisible by a non-zero integer d if there
exists an integer k such that m = k d , i.e. if d divides evenly into m. Equivalently, m is divisible by d if
the remainder of m upon (integer) division by d is zero. We would also express this by saying that d is a
divisor of m. A positive integer p is called prime if its only positive divisors are 1 and p. The one
exception to this rule is the number 1 itself, which is considered to be non-prime. A positive integer that
is not prime is called composite. Euclid showed that there are infinitely many prime numbers. The prime
and composite sequences begin as follows:
Primes: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, …
Composites: 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, …
There are many ways to test a number for primality, but perhaps the simplest is to simply do trial
divisions. Begin by dividing m by 2, and if it divides evenly, then m is not prime. Otherwise, divide by 3,
then 4, then 5, etc. If at any point m is found to be divisible by a number d in the range 2 d m−1, then
halt, and conclude that m is composite. Otherwise, conclude that m is prime. A moment’s thought shows
that one need not do any trial divisions by numbers d which are themselves composite. For instance, if a
trial division by 2 fails (i.e. has non-zero remainder, so m is odd), then a trial division by 4, 6, or 8, or any
even number, must also fail. Thus to test a number m for primality, one need only do trial divisions by
prime numbers less than m. Furthermore, it is not necessary to go all the way up to m−1. One need only
do trial divisions of m by primes p in the range 2 p m . To see this, suppose m >1 is composite.
Then there exist positive integers a and b such that 1 < a < m, 1 < b < m, and m = ab . But if both
a > m and b > m , then ab > m, contradicting that m = ab . Hence one of a or b must be less than
or equal to m .
To implement this process in java you will write a function called isPrime() with the following
signature:
static boolean isPrime(int m, int[] P)
This function will return true or false according to whether m is prime or composite. The array
argument P will contain a sufficient number of primes to do the testing. Specifically, at the time
isPrime() is called, array P must contain (at least) all primes p in the range 2 p m . For instance,
to test m = 53 for primality, one must do successive trial divisions by 2, 3, 5, and 7. We go no further
since 11 > 53 . Thus a precondition for the function call isPrime(53, P) is that P[0] = 2 , P[1] = 3 ,
P[2] = 5, and P[3] = 7 . The return value in this case would be true since all these divisions fail.
Similarly to test m =143 , one must do trial divisions by 2, 3, 5, 7, and 11 (since 13 > 143 ). The
precondition for the function call isPrime(143, P) is therefore P[0] = 2 , P[1] = 3 , P[2] = 5, P[3] = 7 ,
and P[4] =11. The return value in this case would be false since 11 divides 143. Function isPrime()
should contain a loop that steps through array P, doing trial divisions. This loop should terminate when
2
either a trial division succeeds, in which case false is returned, or until the next prime in P is greater
than m , in which case true is returned.
Function main() in this project will read the command line argument n, allocate an int array of length n,
fill the array with primes, then print the contents of the array to stdout according to the format described
below. In the context of function main(), we will refer to this array as Primes[]. Thus array Primes[]
plays a dual role in this project. On the one hand, it is used to collect, store, and print the output data. On
the other hand, it is passed to function isPrime() to test new integers for primality. Whenever
isPrime() returns true, the newly discovered prime will be placed at the appropriate position in array
Primes[]. This process works since, as explained above, the primes needed to test an integer m range
only up to m , and all of these primes (and more) will already be stored in array Primes[] when m is
tested. Of course it will be necessary to initialize Primes[0] = 2 manually, then proceed to test 3, 4, …
for primality using function isPrime().
The following is an outline of the steps to be performed in function main().
Check that the user supplied exactly one command line argument which can be interpreted as a
positive integer n. If the command line argument is not a single positive integer, your program
will print a usage message as specified in the examples below, then exit.
Allocate array Primes[] of length n and initialize Primes[0] = 2 .
Enter a loop which will discover subsequent primes and store them as Primes[1] , Primes[2],
Primes[3] , ..., Primes[n −1] . This loop should contain an inner loop which walks through
successive integers and tests them for primality by calling function isPrime() with appropriate
arguments.
Print the contents of array Primes[] to stdout, 10 to a line separated by single spaces. In other
words Primes[0] through Primes[9] will go on line 1, Primes[10] though Primes[19] will go
on line 2, and so on. Note that if n is not a multiple of 10, then the last line of output will contain
fewer than 10 primes.
Your program, which will be called Prime.java, will produce output identical to that of the sample runs
below. (As usual % signifies the unix prompt.)
% java Prime
Usage: java Prime [PositiveInteger]
% java Prime xyz
Usage: java Prime [PositiveInteger]
% java Prime 10 20
Usage: java Prime [PositiveInteger]
% java Prime 75
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97 101 103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199 211 223 227 229
233 239 241 251 257 263 269 271 277 281
283 293 307 311 313 317 331 337 347 349
353 359 367 373 379
%
3
As you can see, inappropriate command line argument(s) generate a usage message which is similar to
that of many unix commands. (Try doing the more command with no arguments to see such a message.)
Your program will include a function called Usage() having signature
static void Usage()
that prints this message to stderr, then exits. Thus your program will contain three functions in all:
main(), isPrime(), and Usage(). Each should be preceded by a comment block giving it’s name, a
short description of it’s operation, and any necessary preconditions (such as those for isPrime().) See
examples on the webpage.
Attempted Solution
class Prime {
public static void main(String[] args) {
int num1 = 0;
int num2 = 0;
int num3;
for (num1 = 1; num1 < 101; num1++)
System.out.println(num1);
for (num2 = 1; num2 < 101; num1++)
System.out.println(num2);
num3 = num2 % num1;
if (num3 == 0)
System.out.println("The prime numbers are " + num1);
else
System.out.println("The prime numbers are " + (num1 += 1));
}
}
Ben, it looks like you are attempting something that is far beyond your current capability. Start with some much simpler problems. Talk to your teacher and consider taking a more rudimentary course. You don't appear to understand either what the program is supposed to do, or how to write a program that might satisfy the requirements, and nothing we say here can overcome that - you have to develop more understanding of math and programming. We're happy to help with that, but just writing your program here won't help you, and you are too far away from a solution for suggestions to help. I'm sorry if this sounds harsh; honestly, I mean it constructively. Please stay with it - but start simpler.
Your example solution doesn't really follow the problem's specification at all. You should focus first on writing the static boolean isPrime(int m, int[] P) method. All that method needs to do is:
Iterate over the contents of P
If an element evenly divides m, m is composite -- return false
If an element's square is greater than m, m is prime -- return true. It sounds like from the problem description this won't ever happen, P will only have the primes from 2 to the one just before crossing the sqrt(m) boundary
If all the elements of P have been tested, m is prime -- return true
After that you can write main to make the primes array and build it up using the described loop, and finally do argument checking and implement the static void Usage() function to call if the arguments are invalid