Iterative Maximization Algorithm - java

Here is the problem I am currently trying to solve.
There is a maximum value called T. There are then two subvalues, A and B, that are 1 <= A,B <= T. In each round, you can pick either A or B to add to your sum. You can also choose to half that sum entirely in only one of the rounds. You can never exceed T in any round. Given an infinite number of rounds, what is the maximum sum you can get.
Here's an example:
T = 8
A = 5, B = 6
Solution: We first take B, then half the sum getting 3. Then we add A and get 8. So the maximum possible is 8.
The iterative idea I have come up with is: it is basically a tree structure where you keep branching of and trying to build of older sums. I am having trouble trying to figure out a maximization formula.
Is there a brute force solution that will run fast or is there some elegant formula?
Limits: 1 <= A, B <= T. T <= 5,000,000.
EDIT: When you divide, you round down the sum (i.e. 5/2 becomes 2).

The problem can be viewed as a directed graph with T + 1 nodes. Imagine we have T + 1 nodes from 0 to T, and we have an edge from node x to node y if:
x + A = y
x + B = y
x/2 = y
So, in order to answer the question, we need to do a search in the graph, with stating point is node 0.
We can do either a breath first search or depth first search to solve the problem.
Update: as we can only do divided once, so we have to add another state to the graph, which is isDivided. However, the way to solve this problem is not changed.
I will demonstrate the solution with a BFS implementation, DFS is very similar.
class State{
int node, isDivided;
}
boolean[][]visited = new boolean[2][T + 1];
Queue<State> q = new LinkedList();
q.add(new State(0, 0));//Start at node 0, and haven't use division
visited[0][0] = true;
int result = 0;
while(!q.isEmpty()){
State state = q.deque();
result = max(state.node, result);
if(state.node + A <= T && !visited[state.isDivided][state.node + A]){
q.add(new State(node + A , state.isDivided));
visited[state.isDivided][node + A] = true;
}
if(node + B <= T && !visited[state.isDivided][node + B]){
q.add(new State(node + B, state.isDivided));
visited[state.isDivided][node + B] = true;
}
if(state.isDivided == 0 && !visited[state.isDivided][node/2]){
q.add(new State(node/2, 1));
visited[state.isDivided][node/2] = true;
}
}
return result;
Time complexity is O(n)

To summarize your problem setting as I understand it (under the constraint that you can divide by two no more than once):
Add A and B as many times as you want (including 0 each)
Divide by 2, rounding down
Add A and B as many times as you want
The goal is to obtain the largest possible sum, subject to the constraint that the sum is no more than T after any step of the algorithm.
This can be captured neatly in a 5-variable integer program. The five variables are:
a1: The number of times we add A before dividing by 2
b1: The number of times we add B before dividing by 2
s1: floor((A*a1+B*b1)/2), the total sum after the second step
a2: The number of times we add A after dividing by 2
b2: The number of times we add B after dividing by 2
The final sum is s1+A*a2+B*b2, which is constrained not to exceed T; this is what we seek to maximize. All five decision variables must be non-negative integers.
This integer program can be easily solved to optimality by an integer programming solver. For instance, here is how you would solve it with the lpSolve package in R:
library(lpSolve)
get.vals <- function(A, B, T) {
sol <- lp(direction = "max",
objective.in = c(0, 0, 1, A, B),
const.mat = rbind(c(A, B, 0, 0, 0), c(0, 0, 1, A, B), c(-A, -B, 2, 0, 0), c(-A, -B, 2, 0, 0)),
const.dir = c("<=", "<=", "<=", ">="),
const.rhs = c(T, T, 0, -1),
all.int = TRUE)$solution
print(paste("Add", A, "a total of", sol[1], "times and add", B, "a total of", sol[2], "times for sum", A*sol[1]+B*sol[2]))
print(paste("Divide by 2, yielding value", sol[3]))
print(paste("Add", A, "a total of", sol[4], "times and add", B, "a total of", sol[5], "times for sum", sol[3]+A*sol[4]+B*sol[5]))
}
Now we can compute how to get as high of a total sum as possible without exceeding T:
get.vals(5, 6, 8)
# [1] "Add 5 a total of 1 times and add 6 a total of 0 times for sum 5"
# [1] "Divide by 2, yielding value 2"
# [1] "Add 5 a total of 0 times and add 6 a total of 1 times for sum 8"
get.vals(17, 46, 5000000)
# [1] "Add 17 a total of 93 times and add 46 a total of 0 times for sum 1581"
# [1] "Divide by 2, yielding value 790"
# [1] "Add 17 a total of 294063 times and add 46 a total of 3 times for sum 4999999"

I'll use some mathematical approach.
Resume:
You should be able to calculate the max with A,B, T, without iterations (only to get A/B HCD), for T, not to small.
If A or B is an odd number, max = T (with a reserve, I'm not sure you never go over T: see below).
If A and B is even numbers, get C as highest common factor. Then max = round (T/C*2) *C/2 = highest multiple of C/2 below or equal to T
Some explanations:
With the rule: Ap+Bq (without dividing by 2)
1 suppose A and B are primes together, then you can get every integer you want, after the little ones. Then max=T
example: A=11, B=17
2 if A=Cx, and B=Cy, x,y primes together (like 10 and 21), you can get every C multiples, then max= biggest multiple of C below T: round(T/C)*C
example: A=33, B=51 (C=3)
With the rule : you can divide by 2
3 - If C is even number (that is A and B can be divided by 2): max= multiple of C/2 below T: round(T/C*2)*C/2
example: A=22, B=34 (C=2)
4 - Otherwise, you have to find the biggest dividor (highest common factor) of A, B, round(A/2), round (B/2), call it D, max= biggest multiple of D below T: round(T/D)*D
As A and round (A/2) are primes together (idem for B and round (B/2)), then you can get max = T as in case 1 - warning: I'm not sure if you never go past T. To check

We can describe the problem in this way aswell:
f(A , B) = (A * n + B * m) / 2 + (A * x + B * y)
= A * (n * 0.5 + x) + B * (m * 0.5 + y) =
= A * p + B * q
find N: N = f(A , B) and N <= T such that no M: M > N satisfying
the condition exists.
The case without any division by two can easily be represented by n = m = 0 and is thus aswell covered by f.
n and y can be any arbitrary values matching p = n * 0.5 + y (same for q and related values). Note that there are multiple valid solutions as shown in f.
T >= A * p + B * q
r = p * 2, s = q * 2
find integral numbers r, s satisfying the condition
T >= A * r / 2 + B * s / 2
simplify:
T * 2 / B >= A / B * r + s
Thus we know:
(T / B * 2) mod 1 - (A / B * r) mod 1 is minimal and >= 0 for the optimal solution
T * 2 / A >= r >= 0 are the upper and lower bounds for r
(A / B * r) mod 1 = 0, if r = B / gcd(A , B) * n, where n is an integral number
Finding r using these constraints now becomes a trivial task, using binary search. There might be more efficient approach to this, but O(log B) should do for this purpose:
Apply a simple binary-search to find the matching value
in the range [0 , min(T * 2 / A , B / gcd(A , B))
Finding s can easily be done for any corresponding r:
s = roundDown(T * 2 / B - A * r / B)
E.g.:
A = 5
B = 6
T = 8
gcd(A , B) = 1
search-range = [0 , 6)
(T / B * 2) mod 1 = 4 / 6
(A / B * r) mod 1 =
r = 3: 3 / 6 => too small --> decrease r
r = 1: 5 / 6 => too great --> increase r
r = 2: 4 / 6 => optimal solution, r is found
r = 2
s = roundDown(T * 2 / B - A * r / B) = roundDown(3.2 - 1.66) = 1
p = r / 2 = 1 = 1 + 0 = 2 * 0.5 --> n = 1 y = 0 or n = 2 y = 0
q = s / 2 = 0.5 --> n = 0.5 y = 0
8 >= 5 * 1 + 5 * 0.5 * 0 + 0 * 6 + 1 * 0.5 * 6 = 5 + 3
= 5 * 0 + 5 * 0.5 * 2 + 0 * 6 + 1 * 0.5 * 6 = 5 + 3
Advantage of this approach: We can find all solutions in O(log B):
If a value for r is found, all other values r' matching the constraints are as follows: r' = r + B / gcd(A , B) * n. A and B are exchangeable in this approach allowing to optimize even further by using the smaller input value as B.
The rounding of values when the variable is divided by two in your algorithm should only cause minor problems, which can easily be fixed.

Related

Factorial Recursion, answer doesn't make sense on paper?

So I was on codingbat doing recursion excercises and I ran into this
public int factorial(int n) {
if (n == 1) {
return 1;
}
return n * factorial(n-1);
}
I don't understand how this works on paper. as 1 returns 1 thats fine, 2 returns 2, thats fine, 3 returns 6 thats fine, but then factorial(4) returns 24? factorial(5) returns 120?
It doesn't make sense because it is doing it from the last answer of n I assume but not minusing 1? But passes all the tests. So it does 6*4 = 24, rather than 4x(n-1) which wouldn't equal 24? Help?
For any factorial(n), it is computed as n x (n-1) x (n-2) x ... x 1
So for factorial(4) that will be 4 x 3 x 2 x 1 = 24
Recursion is mostly introduced using factorial as an example, so to visualize it will look like
fact(4) = 4 x fact(3)
= 4 x 3 x fact(2)
= 4 x 3 x 2 x fact(1)
= 4 x 3 x 2 x 1 = 24
The recursion repeats until it hits the "anchor" which is the base case of 1
When you're trying to understand recursion, it's good to picture a stack. Every time we're calling return n * factorial(n - 1) we are pushing a value down the stack so we can retrieve it after we're done computing the factorial(n - 1) call. And so on so forth.
factorial(5)
= 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 *factorial(1)
= 5 * 4 * 3 * 2 * 1
= 120

Get the consecutive numbers whose sum matches with given number

I was going through a simple program that takes a number and finds the number of occurrences of consecutive numbers that matches with given number.
For example:
if input is 15, then the consecutive numbers that sum upto 15 are:
1,2,3,4,5
4,5,6
7,8
So the answer is 3 as we have 3 possibilities here.
When I was looking for a solution I found out below answer:
static long process(long input) {
long count = 0;
for (long j = 2; j < input/ 2; j++) {
long temp = (j * (j + 1)) / 2;
if (temp > input) {
break;
}
if ((input- temp) % j == 0) {
count++;
}
}
return count;
}
I am not able to understand how this solves the requirement because this program is using some formula which I am not able to understand properly, below are my doubts:
The for loop starts from 2, what is the reason for this?
long temp = (j * (j + 1)) / 2; What does this logic indicates? How is this helpful to solving the problem?
if ((num - temp) % j == 0) Also what does this indicate?
Please help me in understanding this solution.
I will try to explain this as simple as possible.
If input is 15, then the consecutive numbers that sum upto 15 are:
{1,2,3,4,5} -> 5 numbers
{4,5,6} -> 3 numbers
{7,8} -> 2 numbers
At worst case, this must be less than the Sum of 1st n natural numbers = (n*(n+1) /2.
So for a number 15, there can never be a combination of 6 consecutive numbers summing up to 15 as the sum of 1st 6 numbers =21 which is greater than 15.
Calculate temp: This is (j*(j+1))/2.
Take an example. Let input = 15. Let j =2.
temp = 2*3/2 = 3; #Meaning 1+2 =3
For a 2-number pair, let the 2 terms be 'a+1' and 'a+2'.(Because we know that the numbers are consecutive.)
Now, according to the question, the sum must add up to the number.
This means 2a+3 =15;
And if (15-3) is divisible by 2, 'a' can be found. a=6 -> a+1=7 and a+2=8
Similarly, let a+1 ,a+2 and a+3
a + 1 + a + 2 + a + 3 = 15
3a + 6 = 15
(15-6) must be divisible by 3.
Finally, for 5 consecutive numbers a+1,a+2,a+3,a+4,a+5 , we have
5a + 15 = 15;
(15-15) must be divisible by 5.
So, the count will be changed for j =2,3 and 5 when the input is 15
If the loop were to start from 1, then we would be counting 1 number set too -> {15} which is not needed
To summarize:
1) The for loop starts from 2, what is the reason for this?
We are not worried about 1-number set here.
2) long temp = (j * (j + 1)) / 2; What does this logic indicates? How is this helpful to solving the problem?
This is because of the sum of 1st n natural numbers property as I have
explained the above by taking a+1 and a+2 as 2 consecutive
numbers.
3) if ((num - temp) % j == 0) Also what does this indicate?
This indicates the logic that the input subtracted from the sum of 1st
j natural numbers must be divisible by j.
We need to find all as and ns, that for given b the following is true:
a + (a + 1) + (a + 2) + ... (a + (n - 1)) = b
The left side is an arithmetic progression and can be written as:
(a + (n - 1) / 2) * n = b (*)
To find the limit value of n, we know, that a > 0, so:
(1 + (n - 1) / 2) * n = n(n + 1) / 2 <= b
n(n + 1) <= 2b
n^2 + n + 1/4 <= 2b + 1/4
(n + 1/2)^2 <= 2b + 1/4
n <= sqrt(2b + 1/4) - 1/2
Now we can rewrite (*) to get formula for a:
a = b / n - (n - 1) / 2
Example for b = 15 and n = 3:
15 / 3 - (3 - 1) / 2 = 4 => 4 + 5 + 6 = 15
And now the code:
double b = 15;
for (double n = 2; n <= Math.ceil(Math.sqrt(2 * b + .25) - .5); n++) {
double candidate = b / n - (n - 1) / 2;
if (candidate == (int) candidate) {
System.out.println("" + candidate + IntStream.range(1, (int) n).mapToObj(i -> " + " + (candidate + i)).reduce((s1, s2) -> s1 + s2).get() + " = " + b);
}
}
The result is:
7.0 + 8.0 = 15.0
4.0 + 5.0 + 6.0 = 15.0
1.0 + 2.0 + 3.0 + 4.0 + 5.0 = 15.0
We are looking for consecutive numbers that sum up to the given number.
It's quite obvious that there could be at most one series with a given length, so basically we are looking for those values witch could be the length of such a series.
variable 'j' is the tested length. It starts from 2 because the series must be at least 2 long.
variable 'temp' is the sum of a arithmetic progression from 1 to 'j'.
If there is a proper series then let X the first element. In this case 'input' = j*(X-1) + temp.
(So if temp> input then we finished)
At the last line it checks if there is an integer solution of the equation. If there is, then increase the counter, because there is a series with j element which is a solution.
Actually the solution is wrong, because it won't find solution if input = 3. (It will terminate immediately.) the cycle should be:
for(long j=2;;j++)
The other condition terminates the cycle faster anyway.
NB: loop is starting from 2 because=> (1*(1+1))/2 == 1, which doesn't make sense, i.e, it doesn't effect on the progress;
let, k = 21;
so loop will iterate upto (k/2) => 10 times;
temp = (j*(j+1))/2 => which is, 3 when j =2, 6 when j = 3, and so on (it calculates sum of N natural numbers)
temp > k => will break the loop because, we don't need to iterate the loop when we got 'sum' which is more than 'K'
((k-temp)%j) == 0 => it is basically true when the input subtracted from the sum of first j natural numbers are be divisible by j, if so then increment the count to get total numbers of such equation!
public static long process(long input) {
long count = 0, rest_of_sum;
for (long length = 2; length < input / 2; length++) {
long partial_sum = (length * (length + 1)) / 2;
if (partial_sum > input) {
break;
}
rest_of_sum = input - partial_sum
if (rest_of_sum % length == 0)
count++;
}
return count;
}
input - given input number here it is 15
length - consecutive numbers length this is at-least 2 at max input/2
partial_sum = sum of numbers from 1 to length (which is a*(a+1)/2 for 1 to a numbers) assume this is a partial sequence
rest_of_sum = indicates the balance left in input
if rest of sum is multiple of length meaning is that we can add (rest_of_sum/length) to our partial sequence
lets call (rest_of_sum/length) as k
this only means we can build a sequence here that sums up to our input number
starting with (k+1) , (k+2), ... (k+length)
this can validated now
(k+1) + (k+2) + ... (k+length)
we can reduce this as k+k+k+.. length times + (1+2+3..length)
can be reduced as => k* length + partial_sum
can be reduced as => input (since we verified this now)
So idea here is to increment count every-time we find a length which satisfies this case here
If you put this tweak in it may fix code. I have not extensively tested it. It's an odd one but it puts the code through an extra iteration to fix the early miscalculations. Even 1/20000 would work! Had this been done with floats that got rounded down and 1 added to them I think that would have worked too:
for (long j = 2; j < input+ (1/2); j++) {
In essence you need to only know one formula:
The sum of the numbers m..n (or m to n) (and where n>m in code)
This is ((n-m+1)*(n+m))/2
As I have commented already the code in the original question was bugged.
See here.
Trying feeding it 3. That has 1 occurrence of the consecutive numbers 1,2. It yields 0.
Or 5. That has 2,3 - should yield 1 too - gives 0.
Or 6. This has 1,2,3 - should yield 1 too - gives 0.
In your original code, temp or (j * (j + 1)) / 2 represented the sum of the numbers 1 to j.
1 2 3 4 5
5 4 3 2 1
=======
6 6 6 6 6 => (5 x 6) /2 => 30/2 => 15
As I have shown in the code below - use System.out.println(); to spew out debugging info.
If you want to perfect it make sure m and n's upper limits are half i, and i+1 respectively, rounding down if odd. e.g: (i=15 -> m=7 & n=8)
The code:
class Playground {
private static class CountRes {
String ranges;
long count;
CountRes(String ranges, long count) {
this.ranges = ranges;
this.count = count;
}
String getRanges() {
return this.ranges;
}
long getCount() {
return this.count;
}
}
static long sumMtoN(long m, long n) {
return ((n-m+1)* (n+m))/2;
}
static Playground.CountRes countConsecutiveSums(long i, boolean d) {
long count = 0;
StringBuilder res = new StringBuilder("[");
for (long m = 1; m< 10; m++) {
for (long n = m+1; n<=10; n++) {
long r = Playground.sumMtoN(m,n);
if (d) {
System.out.println(String.format("%d..%d %d",m,n, r));
}
if (i == r) {
count++;
StringBuilder s = new StringBuilder(String.format("[%d..%d], ",m,n));
res.append(s);
}
}
}
if (res.length() > 2) {
res = new StringBuilder(res.substring(0,res.length()-2));
}
res.append("]");
return new CountRes(res.toString(), count);
}
public static void main(String[ ] args) {
Playground.CountRes o = countConsecutiveSums(3, true);
for (long i=3; i<=15; i++) {
o = Playground.countConsecutiveSums(i,false);
System.out.println(String.format("i: %d Count: %d Instances: %s", i, o.getCount(), o.getRanges()));
}
}
}
You can try running it here
The output:
1..2 3
1..3 6
1..4 10
1..5 15
1..6 21
1..7 28
1..8 36
1..9 45
1..10 55
2..3 5
2..4 9
2..5 14
2..6 20
2..7 27
2..8 35
2..9 44
2..10 54
3..4 7
3..5 12
3..6 18
3..7 25
3..8 33
3..9 42
3..10 52
4..5 9
4..6 15
4..7 22
4..8 30
4..9 39
4..10 49
5..6 11
5..7 18
5..8 26
5..9 35
5..10 45
6..7 13
6..8 21
6..9 30
6..10 40
7..8 15
7..9 24
7..10 34
8..9 17
8..10 27
9..10 19
i: 3 Count: 1 Instances: [[1..2]]
i: 4 Count: 0 Instances: []
i: 5 Count: 1 Instances: [[2..3]]
i: 6 Count: 1 Instances: [[1..3]]
i: 7 Count: 1 Instances: [[3..4]]
i: 8 Count: 0 Instances: []
i: 9 Count: 2 Instances: [[2..4], [4..5]]
i: 10 Count: 1 Instances: [[1..4]]
i: 11 Count: 1 Instances: [[5..6]]
i: 12 Count: 1 Instances: [[3..5]]
i: 13 Count: 1 Instances: [[6..7]]
i: 14 Count: 1 Instances: [[2..5]]
i: 15 Count: 3 Instances: [[1..5], [4..6], [7..8]]

Addition in field with finite int elements?

I need to write a function (in Java) which has the following input:
int amountFieldElements
int summandOne
int summandTwo
amountFieldElement describes the amount of int numbers in a range starting from 1 (e.g. 1, 2, 3, 4 or just 1). summandOne is a int from this range, summandTwo can be any non-negative int.
The function has to add summandTwo to summandOne. If the result is bigger then amountFieldElement, it has to start over from 1.
I tried to simply use modulo: (summandOne + summandTwo) % amountFieldElements
But this is often wrong, e.g. (3 + 1) % 4 = 0 but I'd need it to be 4.
Example: If amountFieldElements = 4:
2 + 2 = 4 would stay as 4
3 + 2 = 5 would become 1
4 + 2 = 6 would become 2 etc
or for amountFieldElements = 1
1 + 0 = 1 would stay as 1
1 + 1 = 2 would also be 1
-> any result would be 1 here
something like this will work:
int result = (summandOne + summandTwo) % amountFieldElements;
if (result == 0) result = amountFieldElements;
another method, shorter but harder to understand is:
int result = (summandOne + summandTwo - 1) % amountFieldElements + 1;

O(n) algorithm to find the odd-number-out in array of consecutive integers from 1 to n(not odd numbers)

I'm having a great deal of trouble trying to figure this question out, and the root of that trouble is creating an algorithm of O(n) complexity. Here's the question I'm struggling with:
An Array A of length n contains integers from the range [0, .., n - 1]. However, it only contains n - 1 distinct numbers. So one of the numbers is missing and another number is duplicated. Write a Java method that takes A as an input argument and returns the missing number; the method should run in O(n).
For example, when A = [0, 2, 1, 2, 4], oddOneOut() should return 3; when A = [3, 0, 0, 4, 2, 1], oddOneOut() should return 5.
Obviously this is an easy problem to solve with an O(n2) algorithm, (and most likely O(n), I'm just not seeing it!). I've attempted to solve it using all manner of methods, but to no avail. I'm attempting to solve it in Java, but if you're more comfortable solving it Python, that would be fine as well.
Thank you in advance...
Suppose the number missing is x and the duplicate is y. If you add all numbers, the sum will be:
(n - 1) * n / 2 - x + y
From the above, you can find (x - y).....(1)
Similarly, sum the squares of the numbers. The sum will then be:
(n - 1) * n * (2 * n - 1) / 6 - x2 + y2
From the above you get (x2 - y2)....(2)
(2) / (1) gives (x + y).....(3)
(1) + (3) gives 2 * x and you can thereby find x and y.
Note that in this solution there is O(1) extra storage and is O(n) time complexity. The other solutions above are unnecessarily O(n) extra storage.
Code in mixed C/C++ for some more clarity:
#include <stdio.h>
int findDup(int *arr, int n, int& dup, int& missing)
{
int sum = 0;
int squares = 0;
for (int i = 0; i < n; i++) {
sum += arr[i];
squares += arr[i] * arr[i];
}
sum = (n - 1) * n / 2 - sum; // x - y
squares = (n - 1) * n * (2 * (n - 1) + 1) / 6 - squares; // x^2 - y^2
if (sum == 0) {
// no duplicates
missing = dup = 0;
return -1;
}
missing = (squares / sum + sum) / 2; // ((x^2 - y^2) / (x - y) + (x - y)) / 2 = ((x + y) + (x - y)) / 2 = x
dup = missing - sum; // x - (x - y) = y
return 0;
}
int main(int argc, char *argv[])
{
int dup = 0;
int missing = 0;
int a[] = {0, 2, 1, 2, 4};
findDup(a, sizeof(a) / sizeof(int), dup, missing);
printf("dup = [%d], missing = [%d]\n", dup, missing);
int b[] = {3, 0, 0, 4, 2, 1};
findDup(b, sizeof(b) / sizeof(int), dup, missing);
printf("dup = [%d], missing = [%d]\n", dup, missing);
return 0;
}
Output:
dup = [2], missing = [3]
dup = [0], missing = [5]
Some python code:
def finddup(lst):
sum = 0
sumsq = 0
missing = 0
dup = 0
for item in lst:
sum = sum + item
sumsq = sumsq + item * item
n = len(a)
sum = (n - 1) * n / 2 - sum
sumsq = (n - 1) * n * (2 * (n - 1) + 1) / 6 - sumsq
if sum == 0:
return [-1, missing, dup]
missing = ((sumsq / sum) + sum) / 2
dup = missing - sum
return [0, missing, dup]
found, missing, dup = finddup([0, 2, 1, 2, 4])
if found != -1:
print "dup = " + str(dup) + " missing = " + str(missing)
print finddup([3, 0, 0, 4, 2, 1])
Outputs:
dup = 2 missing = 3
[-1, 0, 0]
Iterate over the array twice: That is still O(n). Create a temporary array of booleans (or a Java BitSet) to hold which numbers you got. Second time you do the loop, check if there is a hole in the array of booleans.
Use a hash set and take a single pass to detect which number is the duplicate. During the same iteration, track the cumulative sum of all the numbers.
Now calculate the expected total if all the numbers were distinct: n * (n - 1) / 2. Subtract the total you found. You will be left with the "missing" number minus the duplicate. Add the duplicate back to get your answer.
Since hash table access is constant time and we're using a single pass, this is O(n). (Note that a single pass isn't strictly necessary: Martijn is correct in noting that a fixed number of passes is still linear complexity.)
This might be of interest, although I'm not certain under what conditions (if any) it performs best. The idea is that we're going to move each element into its correct place in the array (0 to index 0, etc), until it becomes clear what is missing and what is extra.
def findmissing(data):
upto = 0
gap = -1
while upto < len(data):
#print data, gap
if data[upto] == upto:
upto += 1
continue
idx = data[upto]
if idx is None:
upto += 1
continue
data[upto], data[idx] = data[idx], data[upto]
if data[upto] == data[idx]:
print 'found dupe, it is', data[upto]
data[upto] = None
gap = upto
upto += 1
elif data[upto] is None:
gap = upto
return gap
if __name__ == '__main__':
data = range(1000)
import random
missing = random.choice(data)
print missing
data[missing] = data[0]
data[0] = random.choice(data[1:])
random.shuffle(data)
print 'gap is', findmissing(data)
It's O(n) because every step either increments upto or moves a value into its "correct" place in the array, and each of those things can only happen n times.

Division by subtration - dividing the remainder by subtration?

We can divide a number by subtraction and stop at the remainder as shown here.
But how do we continue to divide the remainder by subtraction ? I looked on google and could not find such answers. They don't go beyond the remainder.
For example, lets say we have
7/3.
7-3 = 4
4-3 = 1
So, we have 2 & (1/3). How do we do the 1/3
division using only subtraction or addition ?
REPEAT -
Please note that I dont want to use multiplication or division operators to do this.
You can get additional "digits", up to any arbitrary precision (in any base you desire, I'll use base 10 for simplicity but if you're trying to implement an algorithm you'll probably choose base 2)
1) Perform division as you've illustrated, giving you a quotient (Q=2), a divisor (D=3), and a remainder (R=1)
2) If R=0, you're done
3) Multiply R by your base (10, R now =10)
4) Perform division by subtraction again to find R/D (10/3 = 3+1/3).
5) Divide the resulting quotient by your base (3/10 = 0.3) and add this to what you got from step 1 (now your result is 2.3)
6) Repeat from step 2, dividing the new remainder (1) by 10 again
While it sounds an awful lot like I just said division quite a few times, we're dividing by your base. I used 10 for simplicity, but you'd really use base 2, so step 3 is really a left shift (by 1 bit every time) and step 5 is really a right shift (by 1 bit the first time through, 2 bits the second, and so on).
7/3.
7-3 = 4
4-3 = 1
7/3 = 2 R 1
1*10 = 10
10-3 = 7
7-3 = 4
4-3 = 1
10/3 = 3 R 1
7/3 = 2 + 3/10 R 1
7/3 = 2.3 R 1
1*10 = 10
10-3 = 7
7-3 = 4
4-3 = 1
10/3 = 3 R 1
7/3 = 2.3 + 3/100 R 1
7/3 = 2.33 R 1
And so on until you reach any arbitrary precision.
If you want to keep going to get decimal digits, multiply the remainder by a power of 10.
E.g. if you want 2.333, then you can multiply remainder by 1000, and then repeat the algorithm.
It depends on what you are asking.
If you are asking how to get the end fraction and simply it, let's take a different example.
26 / 6.
26 - 6 = 20 count 1
20 - 6 = 14 count 2
14 - 6 = 8 count 3
8 - 6 = 2 count 4
(In code, this would be accomplished with a for loop)
Afterwards, we would have 4 2/6. To simplify, switch the dividend and divisor:
6 / 2.
6 - 2 = 4 count 1
4 - 2 = 2 count 2
2 - 2 = 0 count 3
If this finishes without a remainder, show as 1 over the count.
In pseudo-code:
int a = 26;
int b = 6;
int tempb = 6;
int left = 26;
int count = 0;
int count2 = 0;
left = a - b;
for(count; left > b; count++){
left -= b;
}
if(left > 0){
for(count2; tempb > left; count2++){
tempb -= left;
}
console.log("The answer is " + count + " and 1/" + count2);
I hope this answers your question!
Here is a complete program that uses only + and -, translate to your language of choice:
module Q where
infixl 14 `÷` `×`
a × 0 = 0
a × 1 = a
a × n = a + a×(n-1)
data Fraction = F Int [Int]
a ÷ 0 = error "division by zero"
a ÷ 1 = F a []
0 ÷ n = F 0 []
a ÷ n
| a >= n = case (a-n) ÷ n of
F r xs -> F (r+1) xs
| otherwise = F 0 (decimals a n)
where
decimals a n = case (a × 10) ÷ n of
F d rest = (d:rest)
instance Show Fraction where
show (F n []) = show n
show (F n xs) = show n ++ "." ++ concatMap show (take 10 xs)
main _ = println (100 ÷ 3)
It is easy to extend this in such a way that the periodic part of the fraction is detected, if any. For this, the decimals should be tuples, where not only the fractional digit itself but also the dividend that gave rise to it is kept.
The printing function could then be adjusted to print infinite fractions like 5.1(43), where 43 would be the periodic part.

Categories