Total of all numbers from 1 to N will always be zero - java

The problem is I have to print all combinations of a sequence of
numbers from 1 to N that will always result to zero. It is allowed
to insert "+" (for adding) and "-" (for subtracting) between each
numbers so that the result will be zero.
//Output
N = 7
1 + 2 - 3 + 4 - 5 - 6 + 7 = 0
1 + 2 - 3 - 4 + 5 + 6 - 7 = 0
1 - 2 + 3 + 4 - 5 + 6 - 7 = 0
1 - 2 - 3 - 4 - 5 + 6 + 7 = 0
So how can I implement this? I am not asking for the actual
codes to do this, just a hint and ideas to solve this will
do. Thank you..

You could also use recursion here. Just remember your current integer, your max integer, your current sum and some kind of history of operations (could also be your final sequence).
In every level you proceed the path in two dirdctions: adding to your sum and substracting from it.
I did a quick implementation in Python, but it should be easy to transfer this to Java or whatever you are using.
def zero_sum(curr, n, seq, sum):
if curr == n and sum == 0:
print(seq)
elif curr < n:
zero_sum(curr + 1, n, seq + " - " + str(curr + 1), sum - (curr + 1))
zero_sum(curr + 1, n, seq + " + " + str(curr + 1), sum + (curr + 1))
zero_sum(1, 7, "1", 1)
Hopefully you get the idea.

The first step is to turn the problem into an entirely regularly formed problem:
n
∑ ±i = -1
i=2
n-2
∑ ±(i+2) = -1
i=0
The term 1 at the start has no prefix +/-. And the walking index better runs from 0 when using a Java array.
So one has n-1 coefficients -1 or +1 for the possible values.
A brute force approach would be to start with the highest values, i = n-2.
The upper/lower bounds for j = 0, ..., i would be ± (i + 1) * (2 + i + 2) / 2, so one can cut the evaluation there - when the till then calculated sum can no longer reach -1.
To represent the coefficients, one could make a new int[n - 1] or simply a new BitSet(n-1).
public void solve(int n) {
int i = n-2;
int sumDone = 0;
BigSet negates = new BitSet(n - 1);
solveRecursively(i, sumDone, negates);
}
private void solveRecursively(int i, int SumDone, BitSet negates) {
if (i < 0) {
if (sumDone == -1) {
System.out.println("Found: " + negates);
}
return;
}
...
}
The interesting, actual (home) work I leave to you. (With BitSet better i = n, ... , 2 by -1 seems simpler though.)

The question here is how much efficiency matters. If you're content to do a brute-force approach, a regression method like the one indicated by holidayfun is a fine way to go, though this will become unwieldy as n gets large.
If performance speed matters, it may be worth doing a bit of math first. The easiest and most rewarding check is whether such a sum is even possible: since the sum of the first n natural numbers is n(n+1)/2, and since you want to divide this into two groups (a "positive" group and a "negative" group) of equal size, you must have that n(n+1)/4 is an integer. Therefore if neither n nor n+1 is divisible by four, stop. You cannot find such a sequence that adds to zero.
This and a few other math tricks might speed up your application significantly, if speed is of the essence. For instance, finding one solution will often help you find others, for large n. For instance, if n=11, then {-11, -10, -7, -5} is one solution. But we could swap the -5 for any combination that adds to 5 that isn't in our set. Thus {-11, -10, -7, -3, -2} is also a solution, and similarly for -7, giving {-11, -10, -5, -4, -3} as a solution (we are not allowed to use -1 because the 1 must be positive). We could continue replacing the -10, the -11, and their components similarly to pick up six more solutions.
This is probably how I'd approach this problem. Use a greedy algorithm to find the "largest" solution (the solution using the largest possible numbers), then keep splitting the components of that solution into successively smaller solutions. It is again fundamentally a recursion problem, but one whose running time decreases with the size of the component under consideration and which at each step generates another solution if a "smaller" solution exists. That being said, if you want every solution then you still have to check non-greedy combinations of your split (otherwise you'd miss solutions like {-7, -4, -3} in your n=7 example). If you only wanted a lot of solutions it would definitely be faster; but to get all of them it may be no better than a brute-force approach.

If I were you I would go for a graph implementation, and DFS algorithm. Imagine you have N nodes that are representing your numbers. Each number is connected to another via an "add" edge, or a "subtract" edge. So you have a fully connected graph. You can start from a node and compute all dfs paths that lead to zero.
For more information about DFS algorithm, you can see the wikipage.
Edit: In order to clarify my solution, the graph you will end up having will be a multigraph, which means that it has more than one edge between nodes. DFS in a multigraph is slightly more complicated, but it is not that hard.

I would suggest a straight forward solution because as you mentioned you are dealing with consecutive integer from 1 to N which are fixed. The only things that vary are the operators in between.
Let's look at your example before we implement a general solution:
For n = 7 you need somehow to produce all possible combinations:
1+2+3+4+5+6+7
1+2+3+4+5+6-7
1+2+3+4+5-6+7
1+2+3+4+5-6-7
...
1-2-3-4-5-6+7
1-2-3-4-5-6-7
If we remove the numbers from above strings/expressions then we'll have:
++++++
+++++-
++++-+
++++--
...
----+-
-----+
------
Which reminds on binary numbers; if we interpret + as 0 and - as 1 the above can be mapped to the binary numbers from 000000 to 111111.
For an input n you'll have n-1 operators inbetween, which means the count of all possible combinations will be 2^n-1.
Putting all the above together something like below can be used to print those which sums are zero:
public static void main(String args[]) throws IOException{
permute(7);
}
public static void permute(int n){
int combinations = (int)Math.pow(2, n-1);
for(int i = 0; i < combinations; i++){
String operators =String.format("%"+(n-1)+"s", Integer.toBinaryString(i)).replace(' ', '0');
int totalSum = 1;
StringBuilder sb = new StringBuilder();
for(int x = 0; x< operators.length(); x++){
sb.append(x+1);
if(operators.charAt(x)=='0'){
sb.append("+");
totalSum = totalSum + (x+2);
}
else{
sb.append("-");
totalSum = totalSum-(x+2);
}
}
sb.append(n);
if(totalSum == 0){
System.out.println(sb.toString() + " = " + totalSum);
}
}
}
Note/Example: String.format("%6s", Integer.toBinaryString(13)).replace(' ', '0') will produce a string with length = 6 from the binary representation of 13 with leading zeros, i.e 001101 instead of 1101 so that we get the required length of the operators.

This is an interesting question. It involves more math than programming because only if you discover the math portion then you may implement an efficient algorithm.
However even before getting into the math we must actually understand what exactly the question is. The question can be rephrased as
Given array [1..n], find all possible two groups (2 subarrays) with equal sum.
So the rules;
sum of [1..n] is n*n(+1)/2
If n*(n+1)/2 is odd then there is no solution.
If your target sum is t then you should not iterate further for lower values than Math.ceil((Math.sqrt(8*t+1)-1)/2) (by solving n from n(n+1)/2 = t equation)
Sorry... I know the question requests Java code but I am not fluent in Java so the code below is in JavaScript. It's good though we can see the results. Also please feel free to edit my answer to include a Java version if you would like to transpile.
So here is the code;
function s2z(n){
function group(t,n){ // (t)arget (n)umber
var e = Math.ceil((Math.sqrt(8*t+1)-1)/2), // don't try after (e)nd
r = [], // (r)esult
d; // (d)ifference
while (n >= e){
d = t-n;
r = d ? r.concat(group(d, d < n ? d : n-1).map(s => s.concat(n)))
: [[n]];
n--;
}
return r;
}
var sum = n*(n+1)/2; // get the sum of series [1..n]
return sum & 1 ? "No solution..!" // if target is odd then no solution
: group(sum/2,n);
}
console.log(JSON.stringify(s2z(7)));
So the result should be [[1,6,7],[2,5,7],[3,4,7],[1,2,4,7],[3,5,6],[1,2,5,6],[1,3,4,6],[2,3,4,5]].
what does this mean..? If you look into that carefuly you will notice that
These are all the possible groups summing up to 14 (half of 28 which is the sum of [1..7].
The first group (at index 0) is complemented by the last group (at index length-1) The second is complemented with the second last and so on...
Now that we have the interim results it's up to us how to display them. This is a secondary and trivial concern. My choice is a simple one as follows.
var arr = [[1,6,7],[2,5,7],[3,4,7],[1,2,4,7],[3,5,6],[1,2,5,6],[1,3,4,6],[2,3,4,5]],
res = arr.reduce((r,s,i,a) => r+s.join("+")+"-"+a[a.length-1-i].join("-")+" = 0 \n","");
console.log(res);
Of course you may put the numbers in an order or might stop halfway preventing the second complements taking positive values while the firsts taking negative values.
This algorithm is not hard tested and i might have overlooked some edges but I believe that this should be a very efficient algorithm. I have calculated up to [1..28] in a very reasonable time resulting 2399784 uniques groups to be paired. The memory is only allocated for the constructed result set despite this is a resursive approach.

It is a good question, but first you must have to try to solve it and show us what you tried so we can help you in the solution, this way you will improve more effectively.
However, the below code is a solution I have write before years, I think the code need improvement but it will help..
public static void main(String[] args) {
String plus = " + ", minus = " - ";
Set<String> operations = new HashSet<>();
operations.add("1" + plus);
operations.add("1" + minus);
// n >= 3
int n = 7;
for (int i = 1; i < n - 1; i++) {
Set<String> newOperation = new HashSet<>();
for (String opt : operations) {
if ((i + 2) == n) {
newOperation.add(opt + (i + 1) + plus + n);
newOperation.add(opt + (i + 1) + minus + n);
} else {
newOperation.add(opt + (i + 1) + plus);
newOperation.add(opt + (i + 1) + minus);
}
}
operations.clear();
operations.addAll(newOperation);
}
evalOperations(operations);
}
private static void evalOperations(Set<String> operations) {
// from JDK1.6, you can use the built-in Javascript engine.
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
try {
for (String opt : operations) {
if ((int) engine.eval(opt) == 0) {
System.out.println(opt + " = 0");
}
}
} catch (ScriptException e) {
e.printStackTrace();
}
}

First, the question is the special case of sum to N.
Second, sum a list to N, could be devided to the first element plus sublist and minus sublist.
Third, if there are only one element in the list, check if n equals the element.
Fourth, make recursion.
Here's the scala implementation, try finishing your java version:
def nSum(nums: List[Int], n: Int, seq: String, res: ListBuffer[String]): Unit =
nums match {
case Nil => if (n == 0) res.append(seq)
case head :: tail => {
nSum(tail, n - head, seq + s" + $head", res)
nSum(tail, n + head, seq + s" - $head", res)
}
}
def zeroSum(nums: List[Int]): List[String] = {
val res = ListBuffer[String]()
nSum(nums.tail, -nums.head, s"${nums.head}", res)
res.map(_ + " = 0").toList
}
val expected = List(
"1 + 2 - 3 + 4 - 5 - 6 + 7 = 0",
"1 + 2 - 3 - 4 + 5 + 6 - 7 = 0",
"1 - 2 + 3 + 4 - 5 + 6 - 7 = 0",
"1 - 2 - 3 - 4 - 5 + 6 + 7 = 0")
assert(expected == zeroSum((1 to 7).toList))

Related

Find max matching 3 Triangular numbers

It's well known that any positive number can be expressed through at most 3 Triangular numbers. (
https://oeis.org/A000217 )
Example:
11 := 10 + 1
12 := 10 + 1 + 1
13 := 10 + 3
14 := 10 + 3 + 1
15 := 15
I am searching the representation of the positive number n through at most 3 possible Triangular summands. There can exist more than one representation of n. I am interested in the one with the greatest summands.
Is there a more effective way than 2 decreasing for and 1 increasing for loops to find the summands?
public void printMaxTriangularNumbers(int n){
int[] tri = createTriangularNumbers(1000);
lbl: for(int i = tri.length-1; ; i--){
int tmp = n - tri[i];
if(tmp == 0){
System.out.println(tri[i]);
break;
}
for(int j=i; j>0; j--){
int tmp2 = tmp - tri[j];
if(tmp2 ==0){
System.out.println(tri[i]);
System.out.println(tri[j]);
break lbl;
}
for(int k=1; k <= j;k++){
if(tmp2 - tri[k] == 0){
System.out.println(tri[i]);
System.out.println(tri[j]);
System.out.println(tri[k]);
break lbl;
}
}
}
}
}
public int[] createTriangularNumbers(int n){
int[] out = new int[n+1];
for(int i=1,sum=0; i<=n;i++){
out[i] = sum += i;
}
return out;
}
As far as I can see, there is no direct formula. An algorithm is needed. For instance, a greedy method does not work. Take for example the value 90:
The greatest triangular number not greater than 90 is 78. Remains 12
The greatest triangular number not greater than 12 is 10. Remains 2
And now it becomes clear we will need 4 terms which is not acceptable.
So I would propose a recursive/backtracking algorithm, where each recursive call deals with one summand only. Each level in the recursion takes first the highest possible triangular number, but if the recursive call fails, it will go for the second largest and dive into recursion again, until there is an acceptable sum.
We can use the formula mentioned at maths.stackexchange.com:
Let Tm be the largest triangular number less than or equal to c.
You can actually get an explicit formula for m, namely:
Here is a snippet that implements the recursion. When running it, you can introduce a value, and the triangular summands will be produced for it.
function getTriangularTerms(n, maxTerms) {
if (maxTerms === 0 && n > 0) return null; // failure: too many terms
if (n == 0) return []; // Ok! Return empty array to which terms can be prepended
// Allow several attempts, each time with a
// lesser triangular summand:
for (let k = Math.floor((Math.sqrt(1+8*n) - 1) / 2); k >= 1; k--) {
let term = k * (k+1)/2;
// Use recursion
let result = getTriangularTerms(n - term, maxTerms - 1);
// If result is not null, we have a match
if (result) return [term, ...result]; // prepend term
}
}
// I/O handling
let input = document.querySelector("input");
let output = document.querySelector("span");
(input.oninput = function () { // event handler for any change in the input
let n = input.value;
let terms = getTriangularTerms(n, 3); // allow 3 terms max.
output.textContent = terms.join("+");
})(); // execute also at page load.
Enter number: <input type="number" value="14"><br>
Terms: <span></span>
Since a triangular number is any number t that satisfies t=x(x+1)/2 for any natural number x, what you're asking is to solve
n = a(a+1)/2 + b(b+1)/2 + c(c+1)/2
and to find the solution (a,b,c) with greatest possible max(a,b,c). You didn't specify that you only allow solutions with 3 triangular numbers, so I will assume you also allow solutions of the form (a,b,c,d) and look for the one with the greatest max(a,b,c,d).
There might be multiple solutions, but one with at most 3 triangular numbers always exists. Since it's possible to form any number with 3 triangular numbers, you can find the largest triangular number t with t<=n, and then it will follow n=t+d, where d=n-t. d is a natural number >=0 and therefore can be composed by 3 triangular numbers itself. Since you're interested in the largest summand, the largest will be t, which can be computed with t=x(x+1)/2 where x=floor((sqrt(1+8n)-1)/2) (obtained by solving the formula n=x(x+1)/2+d).
As a practical example, take n=218. With the formula, we get x=20 and t=210, which indeed is the largest triangular number before 218. The other triangular numbers, in this case, will be 6, 1, 1 since the only way to compute 8 is with those.

Improve performance of string to binary number conversion

This is one of the questions that I faced in competitive programming.
Ques) You have an input String which is in binary format 11100 and you need to count number of steps in which number will be zero. If number is odd -> subtract it by 1, if even -> divide it by 2.
For example
28 -> 28/2
14 -> 14/2
7 -> 7-1
6 -> 6/2
3 -> 3-1
2 -> 2/2
1-> 1-1
0 -> STOP
Number of steps =7
I came up with the following solutions
public int solution(String S) {
// write your code in Java SE 8
String parsableString = cleanString(S);
int integer = Integer.parseInt(S, 2);
return stepCounter(integer);
}
private static String cleanString(String S){
int i = 0;
while (i < S.length() && S.charAt(i) == '0')
i++;
StringBuffer sb = new StringBuffer(S);
sb.replace(0,i,"");
return sb.toString();
}
private static int stepCounter(int integer) {
int counter = 0;
while (integer > 0) {
if (integer == 0)
break;
else {
counter++;
if (integer % 2 == 0)
integer = integer / 2;
else
integer--;
}
}
return counter;
}
The solution to this question looks quite simple and straightforward, however the performance evaluation of this code got me a big ZERO. My initial impressions were that converting the string to int was a bottleneck but failed to find a better solution for this. Can anybody please point out to me the bottlenecks of this code and where it can be significantly improved ?
If a binary number is odd, the last (least significant) digit must be 1, so subtracting 1 is just changing the last digit from 1 to 0 (which, importantly, makes the number even).
If a binary number is even, the last digit must be 0, and dividing by zero can be accomplished by simply removing that last 0 entirely. (Just like in base ten, the number 10 can be divided by ten by taking away the last 0, leaving 1.)
So the number of steps is two steps for every 1 digit, and one step for every 0 digit -- minus 1, because when you get to the last 0, you don't divide by 2 any more, you just stop.
Here's a simple JavaScript (instead of Java) solution:
let n = '11100';
n.length + n.replace(/0/g, '').length - 1;
With just a little more work, this can deal with leading zeros '0011100' properly too, if that were needed.
Number of times you need to subtract is the number of one bits which is Integer.bitCount(). Number of times you need to divide is the position of most-significant bit which is Integer.SIZE (32, total number of bits in integer) minus Integer.numberOfLeadingZeros() minus one (you don't need to divide 1). For zero input I assume, the result should be zero. So we have
int numberOfOperations = integer == 0 ? 0 : Integer.bitCount(integer) +
Integer.SIZE - Integer.numberOfLeadingZeros(integer) - 1;
As per the given condition, we are dividing the number by 2 if it is even which is equivalent to remove the LSB, again if number is odd we are subtracting 1 and making it an even which is equivalent to unset the set bit (changing 1 to 0). Analyzing the above process we can say that the total number of steps required will be the sum of (number of bits i.e. (log2(n) +1)) and number of set bits - 1(last 0 need not to be removed).
C++ code:
result = __builtin_popcount(n) + log2(n) + 1 - 1;
result = __builtin_popcount(n) + log2(n);

Minimum number of powers of 2 to get an Integer?

I was asked below question in an interview:
Every number can be described via the addition and subtraction of powers of 2. For example, 29 = 2^0 + 2^2 + 2^3 + 2^4.
Given an int n, return minimum number of additions
and subtractions of 2^i to get n.
Example 1:
Input: 15
Output: 2
Explanation: 2^4 - 2^0 = 16 - 1 = 15
Example 2:
Input: 8
Output: 1
Example 3:
Input: 0
Output: 0
Below is what I got but is there any way to improve this or is there any better way to solve above problem?
public static int minPowerTwo(int n) {
if (n == 0) {
return 0;
}
if (Integer.bitCount(n) == 1) {
return 1;
}
String binary = Integer.toBinaryString(n);
StringBuilder sb = new StringBuilder();
sb.append(binary.charAt(0));
for (int i = 0; i < binary.length() - 1; i++) {
sb.append('0');
}
int min = Integer.parseInt(sb.toString(), 2);
sb.append('0');
int max = Integer.parseInt(sb.toString(), 2);
return 1 + Math.min(minPowerTwo(n - min), minPowerTwo(max - n));
}
Well... we can deduce that each power of two should be used only once, because otherwise you can get the same result a shorter way, since 2x + 2x = 2x+1, -2x - 2x = -2x+1, and 2x - 2x = 0.
Considering the powers used in order, each one has to change the corresponding bit from an incorrect value to the correct value, because there will be no further opportunities to fix that bit, since each power is used only once.
When you need to add or subtract, the difference is what happens to the higher bits:
000000 000000 111100 111100
+ 100 - 100 + 100 - 100
------ ------ ------ ------
000100 111100 000000 111000
One way, all the higher bits are flipped. The other way they are not.
Since each decision can independently determine the state of all the higher bits, the consequences of choosing between + or - are only relevant in determining the next power of 2.
When you have to choose + or -, one choice will correct 1 bit, but the other choice will correct 2 bits or more, meaning that the next bit that requires correction will be higher.
So, this problem has a very straightforward solution with no dynamic programming or searching or anything like that:
Find the smallest power of 2 that needs correction.
Either add it or subtract it. Pick the option that corrects 2 bits.
Repeat until all the bits are correct
in java, that would look like this. Instead of finding the operations required to make the value, I'll find the operations required to change the value to zero, which is the same thing with opposite signs:
int minPowersToFix(int val) {
int result = 0;
while(val!=0) {
++result;
int firstbit = val&-val; //smallest bit that needs fixed
int pluscase = val+firstbit;
if ((pluscase & (firstbit<<1)) == 0) {
val+=firstbit;
} else {
val-=firstbit;
}
}
return result;
}
And, here is a test case to check whether a solution is correct, written in Java.
(It was written for my solution, which is proven not correct in some case, so I removed that answer, but the test case is still relevant.)
Matt Timmermans's answer passes all the test cases, including negative numbers.
And, Integer.bitCount(val ^ (3 * val)) passes most of them, except when input is Integer.MAX_VALUE.
Code
MinCountOf2PowerTest.java
import org.testng.Assert;
import org.testng.annotations.Test;
public class MinCountOf2PowerTest {
#Test
public void testPositive() {
// no flip,
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("01010001", 2)), 3);
// flip,
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("011", 2)), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("0111", 2)), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("01111", 2)), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.MAX_VALUE), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("01101", 2)), 3);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("011011", 2)), 3);
// flip, there are multiple flippable location,
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("0100000111", 2)), 3);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("010010000000111", 2)), 4);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("0100100000001111111", 2)), 4);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("010011000000001111111", 2)), 5);
}
#Test
public void testZero() {
Assert.assertEquals(MinCountOf2Power.minCount(0), 0);
}
#Test
public void testNegative() {
Assert.assertEquals(MinCountOf2Power.minCount(-1), 1);
Assert.assertEquals(MinCountOf2Power.minCount(-9), 2);
Assert.assertEquals(MinCountOf2Power.minCount(-100), 3);
}
// a positive number has the same result as its negative number,
#Test
public void testPositiveVsNegative() {
for (int i = 1; i <= 1000; i++) {
Assert.assertEquals(MinCountOf2Power.minCount(i), MinCountOf2Power.minCount(-i));
}
Assert.assertEquals(MinCountOf2Power.minCount(Integer.MAX_VALUE), MinCountOf2Power.minCount(-Integer.MAX_VALUE));
}
// corner case - ending 0,
#Test
public void testCornerEnding0() {
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("01110", 2)), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("011110", 2)), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("011100", 2)), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("0111000", 2)), 2);
Assert.assertEquals(MinCountOf2Power.minCount(Integer.parseInt("01110000", 2)), 2);
}
// input from OP's question, refer: https://stackoverflow.com/questions/57797157
#Test
public void testOpInput() {
Assert.assertEquals(MinCountOf2Power.minCount(15), 2);
Assert.assertEquals(MinCountOf2Power.minCount(8), 1);
Assert.assertEquals(MinCountOf2Power.minCount(0), 0);
}
}
Tips:
It's written in Java, and use TestNG.
But you can use JUnit instead simply by replacing the import statement, I guess.
Or translate to other languages by coping the input / output value pairs with specific syntax.
I also found that a positive integer always has the same result as its negative number.
And there is a test case included to proved that.
I wrote this algorithm to solve the problem.
Given N a positive integer:
Find the highest power of 2 A and the lowest power of 2 B, such that A ≤ N ≤ B and A≠B. In other words find in what interval of
consecutive powers of 2 N belongs;
Find if N is closer to A or B, for example by comparing N with the mid value between A and B (It is their average, and since B=2×A the average is 3×A/2 or 1.5×A)
If N is closer to the lower bound (A) than N = A + δ: Append "subtract B" to the explanation message;
If N is closer to the higher bound (B) than N = B - δ: Append "add A" to the explanation message;
Replace N with δ and repeat
The number of iterations minus 1 is the solution you are looking for.
To solve step 1 I wrote this support method that returns the closest power of 2 that is smaller than input, that is A (and we can get B because it is just the double of A)
public int getClosestLowerboundPowerof2 (int n)
{
int i = 1;
while (i<=n/2){
i*=2;
}
return i;
}
The rest is done here:
int operations;
String explanation = "";
if (input>0){
operations = -1;
int n = input, a;
while (n >= 1) {
operations++;
a = getClosestLowerboundPowerof2(n);
if (n > a*1.5) {
explanation += " - "+ a * 2;
n = a * 2 - n;
} else {
explanation += " + " + a;
n -= a;
}
}
System.out.println(input + " = " + explanation.substring(3,explanation.length()) + ", that " + ((operations==1)?"is":"are") + " "+ operations + " operation" + ((operations==1)?"":"s"));
}
else{
System.out.println("Input must be positive");
}
As an example with input = 403 it would print:
403 = 512 - 128 + 16 + 2 + 1, that are 4 operations
Hope I helped!
NOTE: I first misinterpreted the question so I put effort in writing a detailed answer to the wrong problem...
I'm keeping here the original answer because it may be interesting for somebody.
The problem is actually a mathematical argument: how to convert a
number from base 10 to base 2, and they just asked you to implement
an algorithm for that.
Here some theory about this concept and here a method for
reference.
Programmatically I'm interpreting the problem as "Given an integer
print a string of its representation in base 2". For instance given
100 print 2^6 + 2^5 + 2^2. As the linked wiki on radixes explains,
that there is no need for subtractions, so there will only be
additions.
The shortest way to do is to start from n, halve it at each iteration
(i), and write 2^i only if this number (m) is odd. This is tested
with modulo operator (% in java). So the method will be just
this:
public String from10to2(int n){
String str = "";
for (int m = n, i=0; m>=1; m/=2, i++){
str = ((m%2==1)?"+ 2^"+i+" ":"")+str; //"adds '+ 2^i' on top of the string when m is odd, keep str the same otherwise
}
return str.substring(2,str.length()); //debug to remove " + " at the start of the string
}
The content of the for may look inintuitive because I put effort to
make the code as short as possible.
With little effort my method can be generalized to convert a number in
base 10 to any base:
public String baseConverter(int targetBase, int decimalNumber){
String str = "";
for (int m = decimalNumber, i=0; m>=1; m/=targetBase, i++){
str = ((m%targetBase==1)?"+ "+targetBase+"^"+i+" ":"")+str; //"adds '+ x^i' on top of the string when m is odd, keep str the same
otherwise
}
return str.substring(2,str.length()); //debug to remove " + " at the start of the string
}
PS: I didn't use StringBuilder because it's not conceived to append a string on the start. The use of the String concatenation as I
did is argument of debate (someone approve it, other don't).
I guess
For example, 29 = 2^0 + 2^2 + 2^3 + 2^4
is not a correct example in the context of this question. As far as I understand, I should be able to do like
29 = 2^5 - 2^2 + 2^0
Alright, basically this is a math problem. So if math isn't your best suit like me then i would advise you to consider logarithm in the first place whenever you see exponentials in a question. Sometimes it is very useful like in this case since it reduces this problem to a sort of coin change problem with dynamical denominators and also subtraction is allowed.
First I need to find the biggest n that's close to the target.
Lets find the exact n value in 2^n = 29 which is basically log
(2^n) = log 29, which is n log 2 = log 29 so n = log 29 / log
2. Which happens to be 4.857980995127573 and now i know that i
will start with by rounding it to 5.
2^5 is an overshoot. Now i need to reach 32-29 = 3 and also since 32 > 29 the result, 2^2 will be subtracted.
Now we have 2^5 - 2^2 which is 28 and less than 29. Now we need to add the next result and our target is 1.
Ok here is a simple recursive code in JS. I haven't fully tested but seemingly applies the logic just fine.
function pot(t, pr = 0){ // target and previous result
var d = Math.abs(t - pr), // difference
n = Math.round(Math.log(d)/Math.log(2)), // the n figure
cr = t > pr ? pr + 2**n // current result
: pr - 2**n;
return t > cr ? `2^${n} + ` + pot(t, cr) // compose the string result
: t < cr ? `2^${n} - ` + pot(t, cr)
: `2^${n}`;
}
console.log(pot(29));
console.log(pot(1453));
console.log(pot(8565368));
This seems pretty trivial to solve for the cases presented in the examples, like:
0111...1
You can replace any of this pattern with just two powers; i.e.: 7 = 8 - 1 or 15 = 16 - 1 and so on.
You can also deduce that if there are less then 3 consecutive ones, you don't gain much, for example:
0110 (4 + 2)
0110 (8 - 2)
But at the same time, you don't lose anything by doing that operation; in contrast for some cases this is even beneficial:
0110110 - // 54, this has 4 powers
we can take the "last" 0110 and replace it with 1000 - 0010 (8-2) or:
0111000 - 000010 (56 - 2)
but now we can replace 0111 with just two powers : 1000 - 0001.
As such a simple "replace" algorithm can be made:
static int count(int x) {
String s = new StringBuffer(Integer.toBinaryString(x)).reverse().toString() + "0";
Pattern p = Pattern.compile("1+10");
Matcher m = p.matcher(s);
int count = 0;
while (m.find()) {
++count;
s = m.replaceFirst("1");
m = p.matcher(s);
}
return Integer.bitCount(Integer.parseInt(s, 2)) + count;
}

More efficient solution: Project Euler #2: Even Fibonacci Numbers

Problem:
Each new term in the Fibonacci sequence is generated by adding the
previous two terms.
By starting with 1 and 2, the first 10 terms will
be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms.
My code: (which works fine)
public static void main(String[] agrs){
int prevFirst=0;
int prevSecond=1;
int bound=4_000_000;
int evenSum=0;
boolean exceed=false; //when fib numbers > bound
while(!exceed){
int newFib=prevFirst + prevSecond;
prevFirst = prevSecond;
prevSecond = newFib;
if(newFib > bound){
exceed=true;
break;
}
if(newFib % 2 == 0){
evenSum += newFib;
}
}
System.out.println(evenSum);
}
I'm looking for a more efficient algorithm to do this question. Any hints?
When taking the following rules into account:
even + even = even
even + odd = odd
odd + even = odd
odd + odd = even
The parity of the first Fibonacci numbers is:
o o e o o e o o e ...
Thus basically, you simply need to do steps of three. Which is:
(1,1,2)
(3,5,8)
(13,21,34)
Given (a,b,c) this is (b+c,b+2*c,2*b+3*c).
This means we only need to store the two last numbers, and calculate given (a,b), (a+2*b,2*a+3*b).
Thus (1,2) -> (5,8) -> (21,34) -> ... and always return the last one.
This will work faster than a "filter"-approach because that uses the if-statement which reduces pipelining.
The resulting code is:
int b = 1;
int c = 2, d;
long sum = 0;
while(c < 4000000) {
sum += c;
d = b+(c<<0x01);
c = d+b+c;
b = d;
}
System.out.println(sum);
Or the jdoodle (with benchmarking, takes 5 microseconds with cold start, and on average 50 nanoseconds, based on the average of 1M times). Of course the number of instructions in the loop is larger. But the loop is repeated one third of the times.
You can't improve it much more, any improvement that you'll do will be negligible as well as depended on the OS you're running on.
Example:
Running your code in a loop 1M times on my Mac too 73-75ms (ran it a few times).
Changing the condition:
if(newFib % 2 == 0){
to:
if((newFib & 1) == 0){
and running it again a few times I got 51-54ms.
If you'll run the same thing on a different OS you might (and
probably will) get different results.
even if we'll consider the above as an improvement, divide ~20ms in 1M and the "improvement" that you'll get for a single run is meaningless (~20 nanos).
assuming consecutive Fibonacci numbers
a, b,
c = a + b,
d = a + 2b,
e = 2a + 3b,
f = 3a + 5b,
g = 5a + 8b = a + 4(a + 2b) = a + 4d,
it would seem more efficient to use
ef0 = 0, ef1 = 2, efn = efn-2 + 4 efn-1
as I mentioned in my comment there is really no need to further improvement.
I did some measurements
looped 1000000 times the whole thing
measure time in [ms]
ms / 1000000 = ns
so single pass times [ns] are these:
[176 ns] - exploit that even numbers are every third
[179 ns] - &1 instead of %2
[169 ns] - &1 instead of %2 and eliminated if by -,^,&
[edit1] new code
[105 ns] - exploit that even numbers are every third + derived double iteration of fibonaci
[edit2] new code
[76 ns] - decreased operand count to lower overhead and heap trashing
the last one clearly wins on mine machine (although I would expect that the first one will be best)
all was tested on Win7 x64 AMD A8-5500 3.2GHz
App with no threads 32-bit compiler BDS2006 Trubo C++
1,2 are nicely mentioned in Answers here already so I comment just 3:
s+=a&(-((a^1)&1));
(a^1) negates lovest bit
((a^1)&1) is 1 for even and 0 for odd a
-((a^1)&1)) is -1 for even and 0 for odd a
-1 is 0xFFFFFFFF so anding number by it will not change it
0 is 0x00000000 so anding number by it will be 0
hence no need for if
also instead of xor (^) you can use negation (!) but that is much slower on mine machine
OK here is the code (do not read further if you want to code it your self):
//---------------------------------------------------------------------------
int euler002()
{
// Each new term in the Fibonacci sequence is generated by adding the previous two terms.
// By starting with 1 and 2, the first 10 terms will be: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
// By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
int a,a0=0,a1=1,s=0,N=4000000;
/*
//1. [176 ns]
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // even
for (;a<N;)
{
s+=a;
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // even
}
//2. [179 ns]
for (;;)
{
a=a0+a1; a0=a1; a1=a;
if (a>=N) break;
if ((a&1)==0) s+=a;
}
//3. [169 ns]
for (;;)
{
a=a0+a1; a0=a1; a1=a;
if (a>=N) break;
s+=a&(-((a^1)&1));
}
//4. [105 ns] // [edit1]
a0+=a1; a1+=a0; a=a1; // 2x
for (;a<N;)
{
s+=a; a0+=a1; a1+=a0; // 2x
a=a0+a1; a0=a1; a1=a; // 1x
}
*/
//5. [76 ns] //[ edit2]
a0+=a1; a1+=a0; // 2x
for (;a1<N;)
{
s+=a1; a0+=a1; a1+=a0; // 2x
a=a0; a0=a1; a1+=a; // 1x
}
return s;
}
//---------------------------------------------------------------------------
[edit1] faster code add
CommuSoft suggested to iterate more then 1 number per iteration of fibonaci to minimize operations.
nice idea but code in his comment does not give correct answers
I tweaked a little mine so here is the result:
[105 ns] - exploit that even numbers are every third + derived double iteration of fibonaci
this is almost twice the speedup of 1. from which it is derived
look for [edit1] in code or look for //4.
[edit2] even faster code add
- just reorder of some variable and operation use for more speed
- [76 ns] decreased operand count to lower overhead and heap trashing
if you check Fibonacci series, for even numbers 2 8 34 144 610 you can see that there is a fantastic relation between even numbers, for example:
34 = 4*8 + 2,
144 = 34*4 + 8,
610 = 144*4 + 34;
this means that next even in Fibonacci can be expressed like below
Even(n)=4*Even(n-1)+E(n-2);
in Java
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
for(int a0 = 0; a0 < t; a0++){
long n = in.nextLong();
long a=2;
long b=8;
long c=0;
long sum=10;
while(b<n)
{
sum +=c;
c=b*4+a;
a=b;
b=c;
}
System.out.println(sum);
}
}
F(n) be the nth Fibonnaci number i.e F(n)=F(n-1)+F(n-2)
Lets say that F(n) is even, then
F(n) = F(n-1) + F(n-2) = F(n-2) + F(n-3) + F(n-2)
F(n) = 2F(n-2) + F(n-3)
--This proves the point that every third term is even (if F(n-3) is even, then F(n) must be even too)
F(n) = 2[F(n-3) + F(n-4)] + F(n-3)
= 3F(n-3) + 2F(n-4)
= 3F(n-3) + 2F(n-5) + 2F(n-6)
From eq.1:
F(n-3) = 2F(n-5) + F(n-6)
2F(n-5) = F(n-3) - F(n-6)
F(n) = 3F(n-3) + [F(n-3) - F(n-6)] + 2F(n-6)
= 4F(n-3) + F(n-6)
If the sequence of even numbers consists of every third number (n, n-3, n-6, ...)
Even Fibonacci sequence:
E(k) = 4E(k-1) + E(k-2)
Fib Sequence F= {0,1,1,2,3,5,8.....}
Even Fib Sequence E={0,2,8,.....}
CODE:
public static long findEvenFibSum(long n){
long term1=0;
long term2=2;
long curr=0;
long sum=term1+term2;
while((curr=(4*term2+term1))<=n){
sum+=curr;
term1=term2;
term2=curr;
}
return sum;
}
The answer for project Euler problem 2 is(in Java):
int x = 0;
int y = 1;
int z = x + y;
int sumeven = 0;
while(z < 4000000){
x = y;
y = z;
z = x + y;
if(z % 2 == 0){
sumeven += z; /// OR sumeven = sumeven + z
}
}
System.out.printf("sum of the even-valued terms: %d \n", sumeven);
This is the easiest answer.

How to find the next lower integer (with the same number of 1s)

How to find the next lower binary number for an integer (same number of 1s)? For example: if given input number n = 10 (1010), the function should return 9 (1001), or n = 14 (1110) then return 13 (1101), or n = 22 (10110) then return 21 (10101), n = 25 (11001) then return 22 (10110)... etc.
You can do this.
static int nextLower(int n) {
int bc = Integer.bitCount(n);
for (int i = n - 1; i > 0; i--)
if (Integer.bitCount(i) == bc)
return i;
throw new RuntimeException(n+" is the lowest with a bit count of "+bc);
}
Of course if this is homework you are going to have trouble convincing someone you wrote this ;)
For the sake of clarity, in this answer I will use the term 'cardinality' to indicate the number of 1s in the binary representation of a number.
One (obvious) way is to run a downwards loop, and seek for the first number with the same cardinality as your input (just like Peter Lawrey suggested).
I don't think this is inefficient, because I guess the output number is always pretty close to the input. More precisely, all you have to do is to find the rightmost '10' bit sequence, and change it to '01'. Then replace the right part with a number having all 1s at its left, as many as you can, without breaking the postcondition. This brings us to another solution, which consists in converting the number to a binary string (like user2573153 showed you), performing the replacement (with a regular expression, maybe), and then converting back to int.
A slightly faster version of Peter's algorithm should be the following, which performs on integers the manipulation I proposed you for strings:
static int nextLower(int n) {
int fixPart = 0;
int shiftCount = 0;
while ((n & 3) != 2) {
if (n == 0) {
throw new IllegalArgumentException(
fixPart + " is the lowest number with its cardinality");
}
fixPart |= (n & 1) << shiftCount;
shiftCount += 1;
n /= 2;
}
int fixZeros = shiftCount - Integer.bitCount(fixPart);
return ((n ^ 3) << shiftCount) | (((1 << shiftCount) - 1) & ~((1 << fixZeros) - 1));
}
which is O(log n) rather than O(n), but it's definitely harder to understand, and may also be practically slower, due to its complexity. Anyway, you could only notice a difference if you try with some huge difficult number.
EDIT I tried a little benchmark, and found that this code is 67% faster than Peter Lawrey's when applied consecutively to all numbers from 2 to 100,000,000. I don't think this is enough to justify the increased code complexity.
I like such binary task, so to find next lower number you should find right most 1 followed by 0 and exchange them,. UPDATE: you need to "reorder" the rest part of number with 1s at left and 0s at right
10 1010 ->
9 1001
14 1110 ->
13 1101
25 11001 ->
22 10110
here is sample code:
int originalValue = 25;
int maskToCheck = 2; // in binary 10b
int clearingMask = 1;
int settingMask = 0;
int zeroCount = 0;
while (maskToCheck > 0)
{
if ( (originalValue&(maskToCheck|(maskToCheck>>1))) == maskToCheck ) // we found such
{
int newValue = originalValue&(~maskToCheck); // set 1 with 0
newValue = newValue&(~clearingMask)|(settingMask<<zeroCount); // clear all the rest bits, and set most valuable ones
newValue = newValue|(maskToCheck>>1); // set 0 with 1
System.out.println("for " + originalValue + " we found " + newValue);
break;
}
else
{
if ( (originalValue&(maskToCheck>>1)) > 0) // we have 1 bit in cleared part
settingMask = (settingMask<<1) | 1;
else
zeroCount++;
maskToCheck = maskToCheck<<1; // try next left bits
clearingMask = (clearingMask<<1)|1;
}
}

Categories

Resources