Find shortest sequence of mathematical operations
I'm mathematically trying to determine the shortest sequence of moves to reach a desired numerical result. I have two functions, both of which multiply a number by 2, and minus the value of the other number.
I've included my code so far, which has me manually calling the two functions to obtain the desired result; however, I would like help figuring out the logic to do this automatically with a loop.
function findShortestSequence(number)
let left = 0;
let right = 1;
let moves = ;
const moveLeft = () =>
moves.push('L');
left = 2 * left - right;
const moveRight = () =>
moves.push('R');
right = 2 * right - left;
moveLeft();
moveLeft();
moveRight();
moveLeft();
console.log(left, right, moves);
findShortestSequence(-11)
javascript algorithm
add a comment |
I'm mathematically trying to determine the shortest sequence of moves to reach a desired numerical result. I have two functions, both of which multiply a number by 2, and minus the value of the other number.
I've included my code so far, which has me manually calling the two functions to obtain the desired result; however, I would like help figuring out the logic to do this automatically with a loop.
function findShortestSequence(number)
let left = 0;
let right = 1;
let moves = ;
const moveLeft = () =>
moves.push('L');
left = 2 * left - right;
const moveRight = () =>
moves.push('R');
right = 2 * right - left;
moveLeft();
moveLeft();
moveRight();
moveLeft();
console.log(left, right, moves);
findShortestSequence(-11)
javascript algorithm
add a comment |
I'm mathematically trying to determine the shortest sequence of moves to reach a desired numerical result. I have two functions, both of which multiply a number by 2, and minus the value of the other number.
I've included my code so far, which has me manually calling the two functions to obtain the desired result; however, I would like help figuring out the logic to do this automatically with a loop.
function findShortestSequence(number)
let left = 0;
let right = 1;
let moves = ;
const moveLeft = () =>
moves.push('L');
left = 2 * left - right;
const moveRight = () =>
moves.push('R');
right = 2 * right - left;
moveLeft();
moveLeft();
moveRight();
moveLeft();
console.log(left, right, moves);
findShortestSequence(-11)
javascript algorithm
I'm mathematically trying to determine the shortest sequence of moves to reach a desired numerical result. I have two functions, both of which multiply a number by 2, and minus the value of the other number.
I've included my code so far, which has me manually calling the two functions to obtain the desired result; however, I would like help figuring out the logic to do this automatically with a loop.
function findShortestSequence(number)
let left = 0;
let right = 1;
let moves = ;
const moveLeft = () =>
moves.push('L');
left = 2 * left - right;
const moveRight = () =>
moves.push('R');
right = 2 * right - left;
moveLeft();
moveLeft();
moveRight();
moveLeft();
console.log(left, right, moves);
findShortestSequence(-11)
function findShortestSequence(number)
let left = 0;
let right = 1;
let moves = ;
const moveLeft = () =>
moves.push('L');
left = 2 * left - right;
const moveRight = () =>
moves.push('R');
right = 2 * right - left;
moveLeft();
moveLeft();
moveRight();
moveLeft();
console.log(left, right, moves);
findShortestSequence(-11)
function findShortestSequence(number)
let left = 0;
let right = 1;
let moves = ;
const moveLeft = () =>
moves.push('L');
left = 2 * left - right;
const moveRight = () =>
moves.push('R');
right = 2 * right - left;
moveLeft();
moveLeft();
moveRight();
moveLeft();
console.log(left, right, moves);
findShortestSequence(-11)
javascript algorithm
javascript algorithm
edited Nov 13 '18 at 10:58
AnonymousSB
asked Nov 13 '18 at 10:27
AnonymousSBAnonymousSB
2,229221
2,229221
add a comment |
add a comment |
5 Answers
5
active
oldest
votes
I was just looking at -11, and considering 11 being 1011 in binary, which resembles your manual solution of LLRL, just backwards. Tests suggest that this may be the key for negative numbers: get their absolute value, and start shifting towards the right until it becomes zero. When you shift out an 1, move to the left, when you shift out a 0, move to the right. The last step will be a left-move, and the result goes into left
.
Then I just checked what about positive numbers, simply swapping the moves (because leaving them in place would provide the negative result) and it appeared to generate one number above the goal. So I just subtracted one from the original and it started to work. Of course this time the last step is going to be a right-move, and result goes into right
:
function findShortestSequence(number) (org==right));
for(var i=-20;i<=20;i++)
findShortestSequence(i);
While I do not chase to provide a full explanation, I can provide some pieces which one may find useful:
- the "subtract 1 if positive" part feels like creating anti-two's complement number (in two's complement, in case of positive number you do not do anything, and in case of negative number you get its positive pair, invert its bits, and add 1 to the result)
- from a distance the "multiply by 2 and do a fix" is not that extreme:
if one somehow ends up with10001001
(137) and1001
is the fixer, then multiply by 2 shifts everything to the left (100010010
, 274), and if you want to keep that0001001
part in its original place, subtracting the fixer "locally divides" that part back to its original place (100010010
-1001
=100001001
), this is more or less whatmoveRight
does to positive numbers - updating the fixer is more convoluted, though some parts of it do resemble the previous idea: 2*
1001
becomes10010
, and subtracting10001001
fixes back1001
on the lower places, and also introduces that1
from the beginning at high places. The nasty part is that10001001
is clearly larger than10010
, so the result is a negative number, and in fact the fixer (left
in case of a positive target number) has never been1001
, because at its very first update ever, it becomes "2*0
-something" (where "something" is a positive number, asright
starts from 1). Indeed, looking at the example loop,left
always seems to end up being non-positive, andright
seems to be non-negative - the anti-two's complement thing also uglifies the picture, it may be cleaner to think about negative target numbers first, as there the fixer (
right
) is non-negative, andpositive*2-negative
also stays positive:...11110001001
(left
) and1001
(right
),...11110001001
*2 is...111100010010
, and...111100010010
-1001
=...111100001001
, first part of the mission is accomplished (keeping the1001
pattern in place)
and if the goal is to have...1110010001001
later (after 2moveLeft
-s), thenmoveRight
really does1001
*2=10010
,10010
-...11110001001
(-119)=10001001
, which is exactly what is needed to extend the1001
pattern into10001001
for the 8 lowest places) - about being "shortest": the fastest growing part is
moveRight
, ifleft
remains 0 all the time,right
jumps to the next power of two each step, soceil(log2(number))
steps are needed to reach or surpass the given number, which equals to the number of significant binary digits required represent the number, which equals the steps taken by the loop.
That is a great observation about using bitwise operators. One slight modification I've made is to get rid of theif(org <= 0)
statement, and replace themoveLeft()
andmoveRight()
with ternaries.
– AnonymousSB
Nov 13 '18 at 21:27
@AnonymousSB as I had some doubts about the "look, it is easy" explanation in the other answer, so added some thoughts about what is happening inside
– tevemadar
Nov 14 '18 at 12:35
Caleb Lucas' answer seems to me to fail with positive numbers. Am I misreading it? For example, any power of 2 would include an 'L', when clearly we only need R's. And testing just for 3 and -3 returns LL for both. How could that be?
– גלעד ברקן
Nov 14 '18 at 15:25
@גלעדברקן That answer is simply wrong for positive numbers: returns the sequence producing the corresponding negative number, just mirrored. It fails to work starting from1
, which should result in an empty sequence, asright=1
already (same as for0
, sinceleft=0
already)
– tevemadar
Nov 14 '18 at 15:56
@AnonymousSB this solution is far longer than the short one exactly because it does the calculation too. Unfortunately I did not think that adding(org==left)||(org==right)
into the log-line was an absolute necessity.
– tevemadar
Nov 15 '18 at 22:03
|
show 2 more comments
I think I came to the same conclusion as tevemadar. Here it is in code:
function confirm(str, n)
let l = 0;
let r = 1;
let i = 0;
while(str[i])
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
if ([l, r].includes(n))
return true;
return false;
function f(n)
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
for (let i=-11; i<=11; i++)
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
While at least the faulty accepted answer is completely gone, I remain being puzzled why it is so important for OP to accept an answer which is a different one from mine...
– tevemadar
Nov 15 '18 at 16:19
I accepted this answer because the confirm function provided shows that it generates the correct moves, unless there is something I’m missing?
– AnonymousSB
Nov 15 '18 at 19:20
add a comment |
You could take an iterative approach with a stack for the next state for checking the result.
This approach tests the smallest amount of changes first and then takes a growing count of possibilities.
function findShortestSequence(number)
const
moveLeft = (left, right, moves) => [left * 2 - right, right, [...moves, 'L']],
moveRight = (left, right, moves) => [left, right * 2 - left, [...moves, 'R']],
functions = [moveLeft, moveRight];
var stack = [[0, 1, ]],
left, right, moves;
while ([left, right, moves] = stack.shift())
if (left === number) return moves;
functions.forEach(fn => stack.push(fn(left, right, moves)));
console.log(findShortestSequence(-11));
.as-console-wrapper max-height: 100% !important; top: 0;
add a comment |
Yes, I also completely agree with myself, and find my hint useful (ok, that answer is gone).
If verification is not needed, generating the steps is this simple:
function getSequence(n)
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper max-height: 100% !important; top: 0;
I really do appreciate your effort, and original observation about it being binary. This solution is much more succinct to @גלעדברקן's answer, and provides the same results. Quite smart to swap the steps ahead of time. Given that the max binary has a length of 31, I don't see any major issues with the time complexity; however, you could use cut down on one pass with thisreplace
instead.replace(/0|1/g, match => match === '0' ? steps[0] : steps[1])
– AnonymousSB
Nov 15 '18 at 21:03
add a comment |
EDIT: Since we have a correct and proper solution to this question, the pattern of mirroring as applied in CommandBuilder
for positive integers is a misconception and should have never been used: it generates duplicate command strings for some integers. Please see CommandBuilderTwo
for a more appropriate solution.
Given the fact that L = 0 and R = 1, we can convert the desired decimal number, P, into binary and store each digit inversely as 1 for L and 0 for R when negative
Let us also take these factors into consideration. For any given number P:
- P could be a positive number that is the result of (2 ^ N); where 0 < N <= 32
- P could be a positive number that is the result of (2 ^ N) - 1; where 0 < N <= 32
- P could be any other positive number
- P could be any negative number
We can efficiently determine the commands required to build the inputted desired number using the following solution:
public class CommandBuilder
private static String getCommand(long N)
private static boolean isPowerOfTwo(long val)
return (int) Math.ceil( Math.log(val) / Math.log(2))
== (int) Math.floor(Math.log(val) / Math.log(2));
private static boolean isPowerOfTwoMinusOne(long val)
int root = (int) Math.ceil(Math.log(val) / Math.log(2));
return Math.pow(2, root) - 1 == val;
//Driver method
public static void main(String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + getCommand(i) );
System.out.println("The command required to produce -" + i + ": " + getCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + getCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + getCommand(-edge) );
This is a solution equivalent to @tevemadar's description of his solution, albeit in java.
public class CommandBuilderTwo
private static String buildCommand(int N) N == 1)
return "no command can be built";
boolean negated = false;
if(N < 0)
N = -N;
negated = true;
else
--N;
String bin = Integer.toBinaryString(N).split("");
StringBuilder res = new StringBuilder();
if(negated)
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('L');
else
res.append('R');
else
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('R');
else
res.append('L');
//Reverse string built
String command = res.toString();
res = new StringBuilder();
for(int i = command.length() - 1; i >= 0; i--)
res.append(command.charAt(i));
return res.toString();
//Driver method
public static void main (String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + buildCommand(i) );
System.out.println("The command required to produce -" + i + ": " + buildCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + buildCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + buildCommand(-edge) );
If 11 = 1011 = LRLL, and -11 is just LRLL reversed as LLRL, couldn't I just negate the number to positive, convert to binary withtoString(2)
, swap the 1 for L and 0 for R, and reverse the string if it was negated?
– AnonymousSB
Nov 13 '18 at 22:18
@AnonymousSB Sounds like that should work just fine too.
– Caleb Lucas
Nov 13 '18 at 22:31
I think in the case of the following numbers, we discard. 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647
– AnonymousSB
Nov 14 '18 at 1:51
Caleb and @AnonymousSB, I'm confused. How can 3 and -3 have the same set of instructions, LL? It seems to me the code here fails for positive numbers. Did I misunderstand something? For example, any power of 2 would include an 'L', when clearly we only need R's.
– גלעד ברקן
Nov 14 '18 at 15:28
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53278908%2ffind-shortest-sequence-of-mathematical-operations%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
I was just looking at -11, and considering 11 being 1011 in binary, which resembles your manual solution of LLRL, just backwards. Tests suggest that this may be the key for negative numbers: get their absolute value, and start shifting towards the right until it becomes zero. When you shift out an 1, move to the left, when you shift out a 0, move to the right. The last step will be a left-move, and the result goes into left
.
Then I just checked what about positive numbers, simply swapping the moves (because leaving them in place would provide the negative result) and it appeared to generate one number above the goal. So I just subtracted one from the original and it started to work. Of course this time the last step is going to be a right-move, and result goes into right
:
function findShortestSequence(number) (org==right));
for(var i=-20;i<=20;i++)
findShortestSequence(i);
While I do not chase to provide a full explanation, I can provide some pieces which one may find useful:
- the "subtract 1 if positive" part feels like creating anti-two's complement number (in two's complement, in case of positive number you do not do anything, and in case of negative number you get its positive pair, invert its bits, and add 1 to the result)
- from a distance the "multiply by 2 and do a fix" is not that extreme:
if one somehow ends up with10001001
(137) and1001
is the fixer, then multiply by 2 shifts everything to the left (100010010
, 274), and if you want to keep that0001001
part in its original place, subtracting the fixer "locally divides" that part back to its original place (100010010
-1001
=100001001
), this is more or less whatmoveRight
does to positive numbers - updating the fixer is more convoluted, though some parts of it do resemble the previous idea: 2*
1001
becomes10010
, and subtracting10001001
fixes back1001
on the lower places, and also introduces that1
from the beginning at high places. The nasty part is that10001001
is clearly larger than10010
, so the result is a negative number, and in fact the fixer (left
in case of a positive target number) has never been1001
, because at its very first update ever, it becomes "2*0
-something" (where "something" is a positive number, asright
starts from 1). Indeed, looking at the example loop,left
always seems to end up being non-positive, andright
seems to be non-negative - the anti-two's complement thing also uglifies the picture, it may be cleaner to think about negative target numbers first, as there the fixer (
right
) is non-negative, andpositive*2-negative
also stays positive:...11110001001
(left
) and1001
(right
),...11110001001
*2 is...111100010010
, and...111100010010
-1001
=...111100001001
, first part of the mission is accomplished (keeping the1001
pattern in place)
and if the goal is to have...1110010001001
later (after 2moveLeft
-s), thenmoveRight
really does1001
*2=10010
,10010
-...11110001001
(-119)=10001001
, which is exactly what is needed to extend the1001
pattern into10001001
for the 8 lowest places) - about being "shortest": the fastest growing part is
moveRight
, ifleft
remains 0 all the time,right
jumps to the next power of two each step, soceil(log2(number))
steps are needed to reach or surpass the given number, which equals to the number of significant binary digits required represent the number, which equals the steps taken by the loop.
That is a great observation about using bitwise operators. One slight modification I've made is to get rid of theif(org <= 0)
statement, and replace themoveLeft()
andmoveRight()
with ternaries.
– AnonymousSB
Nov 13 '18 at 21:27
@AnonymousSB as I had some doubts about the "look, it is easy" explanation in the other answer, so added some thoughts about what is happening inside
– tevemadar
Nov 14 '18 at 12:35
Caleb Lucas' answer seems to me to fail with positive numbers. Am I misreading it? For example, any power of 2 would include an 'L', when clearly we only need R's. And testing just for 3 and -3 returns LL for both. How could that be?
– גלעד ברקן
Nov 14 '18 at 15:25
@גלעדברקן That answer is simply wrong for positive numbers: returns the sequence producing the corresponding negative number, just mirrored. It fails to work starting from1
, which should result in an empty sequence, asright=1
already (same as for0
, sinceleft=0
already)
– tevemadar
Nov 14 '18 at 15:56
@AnonymousSB this solution is far longer than the short one exactly because it does the calculation too. Unfortunately I did not think that adding(org==left)||(org==right)
into the log-line was an absolute necessity.
– tevemadar
Nov 15 '18 at 22:03
|
show 2 more comments
I was just looking at -11, and considering 11 being 1011 in binary, which resembles your manual solution of LLRL, just backwards. Tests suggest that this may be the key for negative numbers: get their absolute value, and start shifting towards the right until it becomes zero. When you shift out an 1, move to the left, when you shift out a 0, move to the right. The last step will be a left-move, and the result goes into left
.
Then I just checked what about positive numbers, simply swapping the moves (because leaving them in place would provide the negative result) and it appeared to generate one number above the goal. So I just subtracted one from the original and it started to work. Of course this time the last step is going to be a right-move, and result goes into right
:
function findShortestSequence(number) (org==right));
for(var i=-20;i<=20;i++)
findShortestSequence(i);
While I do not chase to provide a full explanation, I can provide some pieces which one may find useful:
- the "subtract 1 if positive" part feels like creating anti-two's complement number (in two's complement, in case of positive number you do not do anything, and in case of negative number you get its positive pair, invert its bits, and add 1 to the result)
- from a distance the "multiply by 2 and do a fix" is not that extreme:
if one somehow ends up with10001001
(137) and1001
is the fixer, then multiply by 2 shifts everything to the left (100010010
, 274), and if you want to keep that0001001
part in its original place, subtracting the fixer "locally divides" that part back to its original place (100010010
-1001
=100001001
), this is more or less whatmoveRight
does to positive numbers - updating the fixer is more convoluted, though some parts of it do resemble the previous idea: 2*
1001
becomes10010
, and subtracting10001001
fixes back1001
on the lower places, and also introduces that1
from the beginning at high places. The nasty part is that10001001
is clearly larger than10010
, so the result is a negative number, and in fact the fixer (left
in case of a positive target number) has never been1001
, because at its very first update ever, it becomes "2*0
-something" (where "something" is a positive number, asright
starts from 1). Indeed, looking at the example loop,left
always seems to end up being non-positive, andright
seems to be non-negative - the anti-two's complement thing also uglifies the picture, it may be cleaner to think about negative target numbers first, as there the fixer (
right
) is non-negative, andpositive*2-negative
also stays positive:...11110001001
(left
) and1001
(right
),...11110001001
*2 is...111100010010
, and...111100010010
-1001
=...111100001001
, first part of the mission is accomplished (keeping the1001
pattern in place)
and if the goal is to have...1110010001001
later (after 2moveLeft
-s), thenmoveRight
really does1001
*2=10010
,10010
-...11110001001
(-119)=10001001
, which is exactly what is needed to extend the1001
pattern into10001001
for the 8 lowest places) - about being "shortest": the fastest growing part is
moveRight
, ifleft
remains 0 all the time,right
jumps to the next power of two each step, soceil(log2(number))
steps are needed to reach or surpass the given number, which equals to the number of significant binary digits required represent the number, which equals the steps taken by the loop.
That is a great observation about using bitwise operators. One slight modification I've made is to get rid of theif(org <= 0)
statement, and replace themoveLeft()
andmoveRight()
with ternaries.
– AnonymousSB
Nov 13 '18 at 21:27
@AnonymousSB as I had some doubts about the "look, it is easy" explanation in the other answer, so added some thoughts about what is happening inside
– tevemadar
Nov 14 '18 at 12:35
Caleb Lucas' answer seems to me to fail with positive numbers. Am I misreading it? For example, any power of 2 would include an 'L', when clearly we only need R's. And testing just for 3 and -3 returns LL for both. How could that be?
– גלעד ברקן
Nov 14 '18 at 15:25
@גלעדברקן That answer is simply wrong for positive numbers: returns the sequence producing the corresponding negative number, just mirrored. It fails to work starting from1
, which should result in an empty sequence, asright=1
already (same as for0
, sinceleft=0
already)
– tevemadar
Nov 14 '18 at 15:56
@AnonymousSB this solution is far longer than the short one exactly because it does the calculation too. Unfortunately I did not think that adding(org==left)||(org==right)
into the log-line was an absolute necessity.
– tevemadar
Nov 15 '18 at 22:03
|
show 2 more comments
I was just looking at -11, and considering 11 being 1011 in binary, which resembles your manual solution of LLRL, just backwards. Tests suggest that this may be the key for negative numbers: get their absolute value, and start shifting towards the right until it becomes zero. When you shift out an 1, move to the left, when you shift out a 0, move to the right. The last step will be a left-move, and the result goes into left
.
Then I just checked what about positive numbers, simply swapping the moves (because leaving them in place would provide the negative result) and it appeared to generate one number above the goal. So I just subtracted one from the original and it started to work. Of course this time the last step is going to be a right-move, and result goes into right
:
function findShortestSequence(number) (org==right));
for(var i=-20;i<=20;i++)
findShortestSequence(i);
While I do not chase to provide a full explanation, I can provide some pieces which one may find useful:
- the "subtract 1 if positive" part feels like creating anti-two's complement number (in two's complement, in case of positive number you do not do anything, and in case of negative number you get its positive pair, invert its bits, and add 1 to the result)
- from a distance the "multiply by 2 and do a fix" is not that extreme:
if one somehow ends up with10001001
(137) and1001
is the fixer, then multiply by 2 shifts everything to the left (100010010
, 274), and if you want to keep that0001001
part in its original place, subtracting the fixer "locally divides" that part back to its original place (100010010
-1001
=100001001
), this is more or less whatmoveRight
does to positive numbers - updating the fixer is more convoluted, though some parts of it do resemble the previous idea: 2*
1001
becomes10010
, and subtracting10001001
fixes back1001
on the lower places, and also introduces that1
from the beginning at high places. The nasty part is that10001001
is clearly larger than10010
, so the result is a negative number, and in fact the fixer (left
in case of a positive target number) has never been1001
, because at its very first update ever, it becomes "2*0
-something" (where "something" is a positive number, asright
starts from 1). Indeed, looking at the example loop,left
always seems to end up being non-positive, andright
seems to be non-negative - the anti-two's complement thing also uglifies the picture, it may be cleaner to think about negative target numbers first, as there the fixer (
right
) is non-negative, andpositive*2-negative
also stays positive:...11110001001
(left
) and1001
(right
),...11110001001
*2 is...111100010010
, and...111100010010
-1001
=...111100001001
, first part of the mission is accomplished (keeping the1001
pattern in place)
and if the goal is to have...1110010001001
later (after 2moveLeft
-s), thenmoveRight
really does1001
*2=10010
,10010
-...11110001001
(-119)=10001001
, which is exactly what is needed to extend the1001
pattern into10001001
for the 8 lowest places) - about being "shortest": the fastest growing part is
moveRight
, ifleft
remains 0 all the time,right
jumps to the next power of two each step, soceil(log2(number))
steps are needed to reach or surpass the given number, which equals to the number of significant binary digits required represent the number, which equals the steps taken by the loop.
I was just looking at -11, and considering 11 being 1011 in binary, which resembles your manual solution of LLRL, just backwards. Tests suggest that this may be the key for negative numbers: get their absolute value, and start shifting towards the right until it becomes zero. When you shift out an 1, move to the left, when you shift out a 0, move to the right. The last step will be a left-move, and the result goes into left
.
Then I just checked what about positive numbers, simply swapping the moves (because leaving them in place would provide the negative result) and it appeared to generate one number above the goal. So I just subtracted one from the original and it started to work. Of course this time the last step is going to be a right-move, and result goes into right
:
function findShortestSequence(number) (org==right));
for(var i=-20;i<=20;i++)
findShortestSequence(i);
While I do not chase to provide a full explanation, I can provide some pieces which one may find useful:
- the "subtract 1 if positive" part feels like creating anti-two's complement number (in two's complement, in case of positive number you do not do anything, and in case of negative number you get its positive pair, invert its bits, and add 1 to the result)
- from a distance the "multiply by 2 and do a fix" is not that extreme:
if one somehow ends up with10001001
(137) and1001
is the fixer, then multiply by 2 shifts everything to the left (100010010
, 274), and if you want to keep that0001001
part in its original place, subtracting the fixer "locally divides" that part back to its original place (100010010
-1001
=100001001
), this is more or less whatmoveRight
does to positive numbers - updating the fixer is more convoluted, though some parts of it do resemble the previous idea: 2*
1001
becomes10010
, and subtracting10001001
fixes back1001
on the lower places, and also introduces that1
from the beginning at high places. The nasty part is that10001001
is clearly larger than10010
, so the result is a negative number, and in fact the fixer (left
in case of a positive target number) has never been1001
, because at its very first update ever, it becomes "2*0
-something" (where "something" is a positive number, asright
starts from 1). Indeed, looking at the example loop,left
always seems to end up being non-positive, andright
seems to be non-negative - the anti-two's complement thing also uglifies the picture, it may be cleaner to think about negative target numbers first, as there the fixer (
right
) is non-negative, andpositive*2-negative
also stays positive:...11110001001
(left
) and1001
(right
),...11110001001
*2 is...111100010010
, and...111100010010
-1001
=...111100001001
, first part of the mission is accomplished (keeping the1001
pattern in place)
and if the goal is to have...1110010001001
later (after 2moveLeft
-s), thenmoveRight
really does1001
*2=10010
,10010
-...11110001001
(-119)=10001001
, which is exactly what is needed to extend the1001
pattern into10001001
for the 8 lowest places) - about being "shortest": the fastest growing part is
moveRight
, ifleft
remains 0 all the time,right
jumps to the next power of two each step, soceil(log2(number))
steps are needed to reach or surpass the given number, which equals to the number of significant binary digits required represent the number, which equals the steps taken by the loop.
function findShortestSequence(number) (org==right));
for(var i=-20;i<=20;i++)
findShortestSequence(i);
function findShortestSequence(number) (org==right));
for(var i=-20;i<=20;i++)
findShortestSequence(i);
edited Nov 15 '18 at 22:06
answered Nov 13 '18 at 11:21
tevemadartevemadar
4,3932725
4,3932725
That is a great observation about using bitwise operators. One slight modification I've made is to get rid of theif(org <= 0)
statement, and replace themoveLeft()
andmoveRight()
with ternaries.
– AnonymousSB
Nov 13 '18 at 21:27
@AnonymousSB as I had some doubts about the "look, it is easy" explanation in the other answer, so added some thoughts about what is happening inside
– tevemadar
Nov 14 '18 at 12:35
Caleb Lucas' answer seems to me to fail with positive numbers. Am I misreading it? For example, any power of 2 would include an 'L', when clearly we only need R's. And testing just for 3 and -3 returns LL for both. How could that be?
– גלעד ברקן
Nov 14 '18 at 15:25
@גלעדברקן That answer is simply wrong for positive numbers: returns the sequence producing the corresponding negative number, just mirrored. It fails to work starting from1
, which should result in an empty sequence, asright=1
already (same as for0
, sinceleft=0
already)
– tevemadar
Nov 14 '18 at 15:56
@AnonymousSB this solution is far longer than the short one exactly because it does the calculation too. Unfortunately I did not think that adding(org==left)||(org==right)
into the log-line was an absolute necessity.
– tevemadar
Nov 15 '18 at 22:03
|
show 2 more comments
That is a great observation about using bitwise operators. One slight modification I've made is to get rid of theif(org <= 0)
statement, and replace themoveLeft()
andmoveRight()
with ternaries.
– AnonymousSB
Nov 13 '18 at 21:27
@AnonymousSB as I had some doubts about the "look, it is easy" explanation in the other answer, so added some thoughts about what is happening inside
– tevemadar
Nov 14 '18 at 12:35
Caleb Lucas' answer seems to me to fail with positive numbers. Am I misreading it? For example, any power of 2 would include an 'L', when clearly we only need R's. And testing just for 3 and -3 returns LL for both. How could that be?
– גלעד ברקן
Nov 14 '18 at 15:25
@גלעדברקן That answer is simply wrong for positive numbers: returns the sequence producing the corresponding negative number, just mirrored. It fails to work starting from1
, which should result in an empty sequence, asright=1
already (same as for0
, sinceleft=0
already)
– tevemadar
Nov 14 '18 at 15:56
@AnonymousSB this solution is far longer than the short one exactly because it does the calculation too. Unfortunately I did not think that adding(org==left)||(org==right)
into the log-line was an absolute necessity.
– tevemadar
Nov 15 '18 at 22:03
That is a great observation about using bitwise operators. One slight modification I've made is to get rid of the
if(org <= 0)
statement, and replace the moveLeft()
and moveRight()
with ternaries.– AnonymousSB
Nov 13 '18 at 21:27
That is a great observation about using bitwise operators. One slight modification I've made is to get rid of the
if(org <= 0)
statement, and replace the moveLeft()
and moveRight()
with ternaries.– AnonymousSB
Nov 13 '18 at 21:27
@AnonymousSB as I had some doubts about the "look, it is easy" explanation in the other answer, so added some thoughts about what is happening inside
– tevemadar
Nov 14 '18 at 12:35
@AnonymousSB as I had some doubts about the "look, it is easy" explanation in the other answer, so added some thoughts about what is happening inside
– tevemadar
Nov 14 '18 at 12:35
Caleb Lucas' answer seems to me to fail with positive numbers. Am I misreading it? For example, any power of 2 would include an 'L', when clearly we only need R's. And testing just for 3 and -3 returns LL for both. How could that be?
– גלעד ברקן
Nov 14 '18 at 15:25
Caleb Lucas' answer seems to me to fail with positive numbers. Am I misreading it? For example, any power of 2 would include an 'L', when clearly we only need R's. And testing just for 3 and -3 returns LL for both. How could that be?
– גלעד ברקן
Nov 14 '18 at 15:25
@גלעדברקן That answer is simply wrong for positive numbers: returns the sequence producing the corresponding negative number, just mirrored. It fails to work starting from
1
, which should result in an empty sequence, as right=1
already (same as for 0
, since left=0
already)– tevemadar
Nov 14 '18 at 15:56
@גלעדברקן That answer is simply wrong for positive numbers: returns the sequence producing the corresponding negative number, just mirrored. It fails to work starting from
1
, which should result in an empty sequence, as right=1
already (same as for 0
, since left=0
already)– tevemadar
Nov 14 '18 at 15:56
@AnonymousSB this solution is far longer than the short one exactly because it does the calculation too. Unfortunately I did not think that adding
(org==left)||(org==right)
into the log-line was an absolute necessity.– tevemadar
Nov 15 '18 at 22:03
@AnonymousSB this solution is far longer than the short one exactly because it does the calculation too. Unfortunately I did not think that adding
(org==left)||(org==right)
into the log-line was an absolute necessity.– tevemadar
Nov 15 '18 at 22:03
|
show 2 more comments
I think I came to the same conclusion as tevemadar. Here it is in code:
function confirm(str, n)
let l = 0;
let r = 1;
let i = 0;
while(str[i])
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
if ([l, r].includes(n))
return true;
return false;
function f(n)
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
for (let i=-11; i<=11; i++)
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
While at least the faulty accepted answer is completely gone, I remain being puzzled why it is so important for OP to accept an answer which is a different one from mine...
– tevemadar
Nov 15 '18 at 16:19
I accepted this answer because the confirm function provided shows that it generates the correct moves, unless there is something I’m missing?
– AnonymousSB
Nov 15 '18 at 19:20
add a comment |
I think I came to the same conclusion as tevemadar. Here it is in code:
function confirm(str, n)
let l = 0;
let r = 1;
let i = 0;
while(str[i])
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
if ([l, r].includes(n))
return true;
return false;
function f(n)
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
for (let i=-11; i<=11; i++)
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
While at least the faulty accepted answer is completely gone, I remain being puzzled why it is so important for OP to accept an answer which is a different one from mine...
– tevemadar
Nov 15 '18 at 16:19
I accepted this answer because the confirm function provided shows that it generates the correct moves, unless there is something I’m missing?
– AnonymousSB
Nov 15 '18 at 19:20
add a comment |
I think I came to the same conclusion as tevemadar. Here it is in code:
function confirm(str, n)
let l = 0;
let r = 1;
let i = 0;
while(str[i])
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
if ([l, r].includes(n))
return true;
return false;
function f(n)
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
for (let i=-11; i<=11; i++)
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
I think I came to the same conclusion as tevemadar. Here it is in code:
function confirm(str, n)
let l = 0;
let r = 1;
let i = 0;
while(str[i])
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
if ([l, r].includes(n))
return true;
return false;
function f(n)
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
for (let i=-11; i<=11; i++)
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
function confirm(str, n)
let l = 0;
let r = 1;
let i = 0;
while(str[i])
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
if ([l, r].includes(n))
return true;
return false;
function f(n)
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
for (let i=-11; i<=11; i++)
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
function confirm(str, n)
let l = 0;
let r = 1;
let i = 0;
while(str[i])
if (str[i++] == 'L')
l = 2*l - r;
else
r = 2*r - l;
if ([l, r].includes(n))
return true;
return false;
function f(n)
if ([0, 1].includes(n))
return '';
else if (n > 1)
return (n - 1)
.toString(2)
.split('')
.map(x => x & 1 ? 'R' : 'L')
.reverse()
.join('');
else
return (-n)
.toString(2)
.split('')
.map(x => x & 1 ? 'L' : 'R')
.reverse()
.join('');
for (let i=-11; i<=11; i++)
fi = f(i);
console.log(i + ': ' + fi + ', ' + confirm(fi, i));
answered Nov 14 '18 at 2:20
גלעד ברקןגלעד ברקן
13k21542
13k21542
While at least the faulty accepted answer is completely gone, I remain being puzzled why it is so important for OP to accept an answer which is a different one from mine...
– tevemadar
Nov 15 '18 at 16:19
I accepted this answer because the confirm function provided shows that it generates the correct moves, unless there is something I’m missing?
– AnonymousSB
Nov 15 '18 at 19:20
add a comment |
While at least the faulty accepted answer is completely gone, I remain being puzzled why it is so important for OP to accept an answer which is a different one from mine...
– tevemadar
Nov 15 '18 at 16:19
I accepted this answer because the confirm function provided shows that it generates the correct moves, unless there is something I’m missing?
– AnonymousSB
Nov 15 '18 at 19:20
While at least the faulty accepted answer is completely gone, I remain being puzzled why it is so important for OP to accept an answer which is a different one from mine...
– tevemadar
Nov 15 '18 at 16:19
While at least the faulty accepted answer is completely gone, I remain being puzzled why it is so important for OP to accept an answer which is a different one from mine...
– tevemadar
Nov 15 '18 at 16:19
I accepted this answer because the confirm function provided shows that it generates the correct moves, unless there is something I’m missing?
– AnonymousSB
Nov 15 '18 at 19:20
I accepted this answer because the confirm function provided shows that it generates the correct moves, unless there is something I’m missing?
– AnonymousSB
Nov 15 '18 at 19:20
add a comment |
You could take an iterative approach with a stack for the next state for checking the result.
This approach tests the smallest amount of changes first and then takes a growing count of possibilities.
function findShortestSequence(number)
const
moveLeft = (left, right, moves) => [left * 2 - right, right, [...moves, 'L']],
moveRight = (left, right, moves) => [left, right * 2 - left, [...moves, 'R']],
functions = [moveLeft, moveRight];
var stack = [[0, 1, ]],
left, right, moves;
while ([left, right, moves] = stack.shift())
if (left === number) return moves;
functions.forEach(fn => stack.push(fn(left, right, moves)));
console.log(findShortestSequence(-11));
.as-console-wrapper max-height: 100% !important; top: 0;
add a comment |
You could take an iterative approach with a stack for the next state for checking the result.
This approach tests the smallest amount of changes first and then takes a growing count of possibilities.
function findShortestSequence(number)
const
moveLeft = (left, right, moves) => [left * 2 - right, right, [...moves, 'L']],
moveRight = (left, right, moves) => [left, right * 2 - left, [...moves, 'R']],
functions = [moveLeft, moveRight];
var stack = [[0, 1, ]],
left, right, moves;
while ([left, right, moves] = stack.shift())
if (left === number) return moves;
functions.forEach(fn => stack.push(fn(left, right, moves)));
console.log(findShortestSequence(-11));
.as-console-wrapper max-height: 100% !important; top: 0;
add a comment |
You could take an iterative approach with a stack for the next state for checking the result.
This approach tests the smallest amount of changes first and then takes a growing count of possibilities.
function findShortestSequence(number)
const
moveLeft = (left, right, moves) => [left * 2 - right, right, [...moves, 'L']],
moveRight = (left, right, moves) => [left, right * 2 - left, [...moves, 'R']],
functions = [moveLeft, moveRight];
var stack = [[0, 1, ]],
left, right, moves;
while ([left, right, moves] = stack.shift())
if (left === number) return moves;
functions.forEach(fn => stack.push(fn(left, right, moves)));
console.log(findShortestSequence(-11));
.as-console-wrapper max-height: 100% !important; top: 0;
You could take an iterative approach with a stack for the next state for checking the result.
This approach tests the smallest amount of changes first and then takes a growing count of possibilities.
function findShortestSequence(number)
const
moveLeft = (left, right, moves) => [left * 2 - right, right, [...moves, 'L']],
moveRight = (left, right, moves) => [left, right * 2 - left, [...moves, 'R']],
functions = [moveLeft, moveRight];
var stack = [[0, 1, ]],
left, right, moves;
while ([left, right, moves] = stack.shift())
if (left === number) return moves;
functions.forEach(fn => stack.push(fn(left, right, moves)));
console.log(findShortestSequence(-11));
.as-console-wrapper max-height: 100% !important; top: 0;
function findShortestSequence(number)
const
moveLeft = (left, right, moves) => [left * 2 - right, right, [...moves, 'L']],
moveRight = (left, right, moves) => [left, right * 2 - left, [...moves, 'R']],
functions = [moveLeft, moveRight];
var stack = [[0, 1, ]],
left, right, moves;
while ([left, right, moves] = stack.shift())
if (left === number) return moves;
functions.forEach(fn => stack.push(fn(left, right, moves)));
console.log(findShortestSequence(-11));
.as-console-wrapper max-height: 100% !important; top: 0;
function findShortestSequence(number)
const
moveLeft = (left, right, moves) => [left * 2 - right, right, [...moves, 'L']],
moveRight = (left, right, moves) => [left, right * 2 - left, [...moves, 'R']],
functions = [moveLeft, moveRight];
var stack = [[0, 1, ]],
left, right, moves;
while ([left, right, moves] = stack.shift())
if (left === number) return moves;
functions.forEach(fn => stack.push(fn(left, right, moves)));
console.log(findShortestSequence(-11));
.as-console-wrapper max-height: 100% !important; top: 0;
edited Nov 13 '18 at 12:49
answered Nov 13 '18 at 11:21
Nina ScholzNina Scholz
187k1596172
187k1596172
add a comment |
add a comment |
Yes, I also completely agree with myself, and find my hint useful (ok, that answer is gone).
If verification is not needed, generating the steps is this simple:
function getSequence(n)
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper max-height: 100% !important; top: 0;
I really do appreciate your effort, and original observation about it being binary. This solution is much more succinct to @גלעדברקן's answer, and provides the same results. Quite smart to swap the steps ahead of time. Given that the max binary has a length of 31, I don't see any major issues with the time complexity; however, you could use cut down on one pass with thisreplace
instead.replace(/0|1/g, match => match === '0' ? steps[0] : steps[1])
– AnonymousSB
Nov 15 '18 at 21:03
add a comment |
Yes, I also completely agree with myself, and find my hint useful (ok, that answer is gone).
If verification is not needed, generating the steps is this simple:
function getSequence(n)
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper max-height: 100% !important; top: 0;
I really do appreciate your effort, and original observation about it being binary. This solution is much more succinct to @גלעדברקן's answer, and provides the same results. Quite smart to swap the steps ahead of time. Given that the max binary has a length of 31, I don't see any major issues with the time complexity; however, you could use cut down on one pass with thisreplace
instead.replace(/0|1/g, match => match === '0' ? steps[0] : steps[1])
– AnonymousSB
Nov 15 '18 at 21:03
add a comment |
Yes, I also completely agree with myself, and find my hint useful (ok, that answer is gone).
If verification is not needed, generating the steps is this simple:
function getSequence(n)
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper max-height: 100% !important; top: 0;
Yes, I also completely agree with myself, and find my hint useful (ok, that answer is gone).
If verification is not needed, generating the steps is this simple:
function getSequence(n)
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper max-height: 100% !important; top: 0;
function getSequence(n)
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper max-height: 100% !important; top: 0;
function getSequence(n)
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper max-height: 100% !important; top: 0;
answered Nov 15 '18 at 16:55
tevemadartevemadar
4,3932725
4,3932725
I really do appreciate your effort, and original observation about it being binary. This solution is much more succinct to @גלעדברקן's answer, and provides the same results. Quite smart to swap the steps ahead of time. Given that the max binary has a length of 31, I don't see any major issues with the time complexity; however, you could use cut down on one pass with thisreplace
instead.replace(/0|1/g, match => match === '0' ? steps[0] : steps[1])
– AnonymousSB
Nov 15 '18 at 21:03
add a comment |
I really do appreciate your effort, and original observation about it being binary. This solution is much more succinct to @גלעדברקן's answer, and provides the same results. Quite smart to swap the steps ahead of time. Given that the max binary has a length of 31, I don't see any major issues with the time complexity; however, you could use cut down on one pass with thisreplace
instead.replace(/0|1/g, match => match === '0' ? steps[0] : steps[1])
– AnonymousSB
Nov 15 '18 at 21:03
I really do appreciate your effort, and original observation about it being binary. This solution is much more succinct to @גלעדברקן's answer, and provides the same results. Quite smart to swap the steps ahead of time. Given that the max binary has a length of 31, I don't see any major issues with the time complexity; however, you could use cut down on one pass with this
replace
instead .replace(/0|1/g, match => match === '0' ? steps[0] : steps[1])
– AnonymousSB
Nov 15 '18 at 21:03
I really do appreciate your effort, and original observation about it being binary. This solution is much more succinct to @גלעדברקן's answer, and provides the same results. Quite smart to swap the steps ahead of time. Given that the max binary has a length of 31, I don't see any major issues with the time complexity; however, you could use cut down on one pass with this
replace
instead .replace(/0|1/g, match => match === '0' ? steps[0] : steps[1])
– AnonymousSB
Nov 15 '18 at 21:03
add a comment |
EDIT: Since we have a correct and proper solution to this question, the pattern of mirroring as applied in CommandBuilder
for positive integers is a misconception and should have never been used: it generates duplicate command strings for some integers. Please see CommandBuilderTwo
for a more appropriate solution.
Given the fact that L = 0 and R = 1, we can convert the desired decimal number, P, into binary and store each digit inversely as 1 for L and 0 for R when negative
Let us also take these factors into consideration. For any given number P:
- P could be a positive number that is the result of (2 ^ N); where 0 < N <= 32
- P could be a positive number that is the result of (2 ^ N) - 1; where 0 < N <= 32
- P could be any other positive number
- P could be any negative number
We can efficiently determine the commands required to build the inputted desired number using the following solution:
public class CommandBuilder
private static String getCommand(long N)
private static boolean isPowerOfTwo(long val)
return (int) Math.ceil( Math.log(val) / Math.log(2))
== (int) Math.floor(Math.log(val) / Math.log(2));
private static boolean isPowerOfTwoMinusOne(long val)
int root = (int) Math.ceil(Math.log(val) / Math.log(2));
return Math.pow(2, root) - 1 == val;
//Driver method
public static void main(String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + getCommand(i) );
System.out.println("The command required to produce -" + i + ": " + getCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + getCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + getCommand(-edge) );
This is a solution equivalent to @tevemadar's description of his solution, albeit in java.
public class CommandBuilderTwo
private static String buildCommand(int N) N == 1)
return "no command can be built";
boolean negated = false;
if(N < 0)
N = -N;
negated = true;
else
--N;
String bin = Integer.toBinaryString(N).split("");
StringBuilder res = new StringBuilder();
if(negated)
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('L');
else
res.append('R');
else
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('R');
else
res.append('L');
//Reverse string built
String command = res.toString();
res = new StringBuilder();
for(int i = command.length() - 1; i >= 0; i--)
res.append(command.charAt(i));
return res.toString();
//Driver method
public static void main (String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + buildCommand(i) );
System.out.println("The command required to produce -" + i + ": " + buildCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + buildCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + buildCommand(-edge) );
If 11 = 1011 = LRLL, and -11 is just LRLL reversed as LLRL, couldn't I just negate the number to positive, convert to binary withtoString(2)
, swap the 1 for L and 0 for R, and reverse the string if it was negated?
– AnonymousSB
Nov 13 '18 at 22:18
@AnonymousSB Sounds like that should work just fine too.
– Caleb Lucas
Nov 13 '18 at 22:31
I think in the case of the following numbers, we discard. 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647
– AnonymousSB
Nov 14 '18 at 1:51
Caleb and @AnonymousSB, I'm confused. How can 3 and -3 have the same set of instructions, LL? It seems to me the code here fails for positive numbers. Did I misunderstand something? For example, any power of 2 would include an 'L', when clearly we only need R's.
– גלעד ברקן
Nov 14 '18 at 15:28
add a comment |
EDIT: Since we have a correct and proper solution to this question, the pattern of mirroring as applied in CommandBuilder
for positive integers is a misconception and should have never been used: it generates duplicate command strings for some integers. Please see CommandBuilderTwo
for a more appropriate solution.
Given the fact that L = 0 and R = 1, we can convert the desired decimal number, P, into binary and store each digit inversely as 1 for L and 0 for R when negative
Let us also take these factors into consideration. For any given number P:
- P could be a positive number that is the result of (2 ^ N); where 0 < N <= 32
- P could be a positive number that is the result of (2 ^ N) - 1; where 0 < N <= 32
- P could be any other positive number
- P could be any negative number
We can efficiently determine the commands required to build the inputted desired number using the following solution:
public class CommandBuilder
private static String getCommand(long N)
private static boolean isPowerOfTwo(long val)
return (int) Math.ceil( Math.log(val) / Math.log(2))
== (int) Math.floor(Math.log(val) / Math.log(2));
private static boolean isPowerOfTwoMinusOne(long val)
int root = (int) Math.ceil(Math.log(val) / Math.log(2));
return Math.pow(2, root) - 1 == val;
//Driver method
public static void main(String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + getCommand(i) );
System.out.println("The command required to produce -" + i + ": " + getCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + getCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + getCommand(-edge) );
This is a solution equivalent to @tevemadar's description of his solution, albeit in java.
public class CommandBuilderTwo
private static String buildCommand(int N) N == 1)
return "no command can be built";
boolean negated = false;
if(N < 0)
N = -N;
negated = true;
else
--N;
String bin = Integer.toBinaryString(N).split("");
StringBuilder res = new StringBuilder();
if(negated)
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('L');
else
res.append('R');
else
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('R');
else
res.append('L');
//Reverse string built
String command = res.toString();
res = new StringBuilder();
for(int i = command.length() - 1; i >= 0; i--)
res.append(command.charAt(i));
return res.toString();
//Driver method
public static void main (String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + buildCommand(i) );
System.out.println("The command required to produce -" + i + ": " + buildCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + buildCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + buildCommand(-edge) );
If 11 = 1011 = LRLL, and -11 is just LRLL reversed as LLRL, couldn't I just negate the number to positive, convert to binary withtoString(2)
, swap the 1 for L and 0 for R, and reverse the string if it was negated?
– AnonymousSB
Nov 13 '18 at 22:18
@AnonymousSB Sounds like that should work just fine too.
– Caleb Lucas
Nov 13 '18 at 22:31
I think in the case of the following numbers, we discard. 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647
– AnonymousSB
Nov 14 '18 at 1:51
Caleb and @AnonymousSB, I'm confused. How can 3 and -3 have the same set of instructions, LL? It seems to me the code here fails for positive numbers. Did I misunderstand something? For example, any power of 2 would include an 'L', when clearly we only need R's.
– גלעד ברקן
Nov 14 '18 at 15:28
add a comment |
EDIT: Since we have a correct and proper solution to this question, the pattern of mirroring as applied in CommandBuilder
for positive integers is a misconception and should have never been used: it generates duplicate command strings for some integers. Please see CommandBuilderTwo
for a more appropriate solution.
Given the fact that L = 0 and R = 1, we can convert the desired decimal number, P, into binary and store each digit inversely as 1 for L and 0 for R when negative
Let us also take these factors into consideration. For any given number P:
- P could be a positive number that is the result of (2 ^ N); where 0 < N <= 32
- P could be a positive number that is the result of (2 ^ N) - 1; where 0 < N <= 32
- P could be any other positive number
- P could be any negative number
We can efficiently determine the commands required to build the inputted desired number using the following solution:
public class CommandBuilder
private static String getCommand(long N)
private static boolean isPowerOfTwo(long val)
return (int) Math.ceil( Math.log(val) / Math.log(2))
== (int) Math.floor(Math.log(val) / Math.log(2));
private static boolean isPowerOfTwoMinusOne(long val)
int root = (int) Math.ceil(Math.log(val) / Math.log(2));
return Math.pow(2, root) - 1 == val;
//Driver method
public static void main(String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + getCommand(i) );
System.out.println("The command required to produce -" + i + ": " + getCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + getCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + getCommand(-edge) );
This is a solution equivalent to @tevemadar's description of his solution, albeit in java.
public class CommandBuilderTwo
private static String buildCommand(int N) N == 1)
return "no command can be built";
boolean negated = false;
if(N < 0)
N = -N;
negated = true;
else
--N;
String bin = Integer.toBinaryString(N).split("");
StringBuilder res = new StringBuilder();
if(negated)
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('L');
else
res.append('R');
else
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('R');
else
res.append('L');
//Reverse string built
String command = res.toString();
res = new StringBuilder();
for(int i = command.length() - 1; i >= 0; i--)
res.append(command.charAt(i));
return res.toString();
//Driver method
public static void main (String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + buildCommand(i) );
System.out.println("The command required to produce -" + i + ": " + buildCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + buildCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + buildCommand(-edge) );
EDIT: Since we have a correct and proper solution to this question, the pattern of mirroring as applied in CommandBuilder
for positive integers is a misconception and should have never been used: it generates duplicate command strings for some integers. Please see CommandBuilderTwo
for a more appropriate solution.
Given the fact that L = 0 and R = 1, we can convert the desired decimal number, P, into binary and store each digit inversely as 1 for L and 0 for R when negative
Let us also take these factors into consideration. For any given number P:
- P could be a positive number that is the result of (2 ^ N); where 0 < N <= 32
- P could be a positive number that is the result of (2 ^ N) - 1; where 0 < N <= 32
- P could be any other positive number
- P could be any negative number
We can efficiently determine the commands required to build the inputted desired number using the following solution:
public class CommandBuilder
private static String getCommand(long N)
private static boolean isPowerOfTwo(long val)
return (int) Math.ceil( Math.log(val) / Math.log(2))
== (int) Math.floor(Math.log(val) / Math.log(2));
private static boolean isPowerOfTwoMinusOne(long val)
int root = (int) Math.ceil(Math.log(val) / Math.log(2));
return Math.pow(2, root) - 1 == val;
//Driver method
public static void main(String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + getCommand(i) );
System.out.println("The command required to produce -" + i + ": " + getCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + getCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + getCommand(-edge) );
This is a solution equivalent to @tevemadar's description of his solution, albeit in java.
public class CommandBuilderTwo
private static String buildCommand(int N) N == 1)
return "no command can be built";
boolean negated = false;
if(N < 0)
N = -N;
negated = true;
else
--N;
String bin = Integer.toBinaryString(N).split("");
StringBuilder res = new StringBuilder();
if(negated)
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('L');
else
res.append('R');
else
for (String c: bin)
if((Integer.valueOf(c) & 1) == 1)
res.append('R');
else
res.append('L');
//Reverse string built
String command = res.toString();
res = new StringBuilder();
for(int i = command.length() - 1; i >= 0; i--)
res.append(command.charAt(i));
return res.toString();
//Driver method
public static void main (String args)
for(int i = 0; i <= 25; i++)
System.out.println("The command required to produce " + i + ": " + buildCommand(i) );
System.out.println("The command required to produce -" + i + ": " + buildCommand(-i) );
int edge = Integer.MAX_VALUE;
System.out.println("The command required to produce " + edge + ": " + buildCommand(edge) );
System.out.println("The command required to produce -" + edge + ": " + buildCommand(-edge) );
edited Nov 20 '18 at 21:20
answered Nov 13 '18 at 21:25
Caleb LucasCaleb Lucas
6816
6816
If 11 = 1011 = LRLL, and -11 is just LRLL reversed as LLRL, couldn't I just negate the number to positive, convert to binary withtoString(2)
, swap the 1 for L and 0 for R, and reverse the string if it was negated?
– AnonymousSB
Nov 13 '18 at 22:18
@AnonymousSB Sounds like that should work just fine too.
– Caleb Lucas
Nov 13 '18 at 22:31
I think in the case of the following numbers, we discard. 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647
– AnonymousSB
Nov 14 '18 at 1:51
Caleb and @AnonymousSB, I'm confused. How can 3 and -3 have the same set of instructions, LL? It seems to me the code here fails for positive numbers. Did I misunderstand something? For example, any power of 2 would include an 'L', when clearly we only need R's.
– גלעד ברקן
Nov 14 '18 at 15:28
add a comment |
If 11 = 1011 = LRLL, and -11 is just LRLL reversed as LLRL, couldn't I just negate the number to positive, convert to binary withtoString(2)
, swap the 1 for L and 0 for R, and reverse the string if it was negated?
– AnonymousSB
Nov 13 '18 at 22:18
@AnonymousSB Sounds like that should work just fine too.
– Caleb Lucas
Nov 13 '18 at 22:31
I think in the case of the following numbers, we discard. 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647
– AnonymousSB
Nov 14 '18 at 1:51
Caleb and @AnonymousSB, I'm confused. How can 3 and -3 have the same set of instructions, LL? It seems to me the code here fails for positive numbers. Did I misunderstand something? For example, any power of 2 would include an 'L', when clearly we only need R's.
– גלעד ברקן
Nov 14 '18 at 15:28
If 11 = 1011 = LRLL, and -11 is just LRLL reversed as LLRL, couldn't I just negate the number to positive, convert to binary with
toString(2)
, swap the 1 for L and 0 for R, and reverse the string if it was negated?– AnonymousSB
Nov 13 '18 at 22:18
If 11 = 1011 = LRLL, and -11 is just LRLL reversed as LLRL, couldn't I just negate the number to positive, convert to binary with
toString(2)
, swap the 1 for L and 0 for R, and reverse the string if it was negated?– AnonymousSB
Nov 13 '18 at 22:18
@AnonymousSB Sounds like that should work just fine too.
– Caleb Lucas
Nov 13 '18 at 22:31
@AnonymousSB Sounds like that should work just fine too.
– Caleb Lucas
Nov 13 '18 at 22:31
I think in the case of the following numbers, we discard. 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647
– AnonymousSB
Nov 14 '18 at 1:51
I think in the case of the following numbers, we discard. 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647
– AnonymousSB
Nov 14 '18 at 1:51
Caleb and @AnonymousSB, I'm confused. How can 3 and -3 have the same set of instructions, LL? It seems to me the code here fails for positive numbers. Did I misunderstand something? For example, any power of 2 would include an 'L', when clearly we only need R's.
– גלעד ברקן
Nov 14 '18 at 15:28
Caleb and @AnonymousSB, I'm confused. How can 3 and -3 have the same set of instructions, LL? It seems to me the code here fails for positive numbers. Did I misunderstand something? For example, any power of 2 would include an 'L', when clearly we only need R's.
– גלעד ברקן
Nov 14 '18 at 15:28
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53278908%2ffind-shortest-sequence-of-mathematical-operations%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown