我在数学上尝试确定最短的移动顺序以达到所需的数值结果。我有两个函数,两个函数都将一个数字乘以2,然后减去另一个数字的值。
到目前为止,我已经包含了我的代码,这使我可以手动调用这两个函数以获得所需的结果。但是,我想帮助您弄清楚循环自动执行此操作的逻辑。
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)
答案 0 :(得分:3)
我只是看-11,考虑11是二进制的1011,这与您对LLRL的手动解决方案类似,只是倒退了。测试表明,这可能是负数的关键:获取其绝对值,然后开始向右移动直到变为零。当您移出1时,请移至左侧;当您移出0时,请移至右侧。最后一步是向左移动,结果进入left
。
然后,我只是检查了正数,简单地交换了一下举动(因为将其留在原处会提供负数的结果),它看起来比目标高出一个数。所以我只从原始文件中减去了一个,然后开始工作。当然这次,最后一步将是右移,结果进入right
:
function findShortestSequence(number) {
let org = number;
if(number<=0)number=-number; // work with absolute values when input is not positive
else number--; // work with one less, if input is positive
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;
}
if(org<=0)
while(number!=0){
if(number&1)moveLeft();
else moveRight();
number>>=1;
}
else
while(number!=0){
if(number&1)moveRight();
else moveLeft();
number>>=1;
}
console.log(org, left, right, moves.join(''), (org==left)||(org==right));
}
for(var i=-20;i<=20;i++)
findShortestSequence(i);
虽然我不追求提供完整的解释,但我可以提供一些可能有用的片段:
10001001
(137)结尾并且1001
是固定器,则乘以2将所有内容向左移动(100010010
,274),并且如果要保留该值0001001
部分恢复到其原始位置,减去该部分返回其原始位置的固定器“局部分割”(100010010
-1001
= 100001001
),这或多或少moveRight
对正数的作用1001
变成10010
,减去10001001
后修复1001
较低的位置,并从较高的位置开始介绍1
。令人讨厌的部分是10001001
明显大于10010
,因此结果是一个负数,而实际上固定器(如果目标数为正,则为left
) 1001
,因为在有史以来的第一次更新中,它变为“ 2 * 0
-something”(其中“ something”是正数,因为right
从1开始)。确实,在示例循环中,left
似乎总是以非正数结尾,而right
似乎是非负的right
)是非负数,而positive*2-negative
也保持不变正面:...11110001001
(left
)和1001
(right
),...11110001001
* 2是...111100010010
,而...111100010010
-{{1 }} = {1001
,任务的第一部分完成了(将...111100001001
模式保留在原处)1001
(在2个...1110010001001
-s之后),则moveLeft
确实会moveRight
* 2 = 1001
,{{1 }}-10010
(-119)= 10010
,这正是将...11110001001
模式扩展到10001001
的最低8个位置所需的条件)1001
,如果10001001
始终保持为0,则moveRight
会跳到下一步的二阶幂,所以{{ 1}}步骤需要达到或超过给定的数字,该数字等于表示该数字所需的有效二进制数,它等于循环所采取的步骤。答案 1 :(得分:1)
我认为我得出的结论与特维玛达相同。在代码中:
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));
}
答案 2 :(得分: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; }
答案 3 :(得分:0)
编辑:由于我们对这个问题有正确而正确的解决方案,因此CommandBuilder
中对正整数应用的镜像模式是一种误解,不应使用:它会生成重复的命令字符串对于一些整数。请参阅CommandBuilderTwo
,以获取更合适的解决方案。
鉴于L = 0和R = 1,我们可以将所需的十进制数P转换为二进制数,并且当负数为L时将每个数字反向存储为1,R为0。
让我们也考虑这些因素。对于任何给定的数字P:
我们可以使用以下解决方案有效地确定构建所需输入数字所需的命令:
public class CommandBuilder {
private static String getCommand(long N)
{
if(N == 0 || N == 1 )
return "no command can be returned because of formulae constraints";
boolean negated = false;
boolean isPowerOfTwo = false;
boolean isPowerOfTwoMinusOne = false;
if(N < 0){
N = -N;
negated = true;
} else {
isPowerOfTwo = isPowerOfTwo(N);
isPowerOfTwoMinusOne = isPowerOfTwoMinusOne(N);
}
//Extract the binary representation as L's and R's
ArrayList<String> commands = new ArrayList<>();
while (N > 0) {
if( N % 2 == 0) {
commands.add("R");
} else {
if(isPowerOfTwo)
commands.add("R");
else
commands.add("L");
}
N /= 2;
}
StringBuilder finalCommand = new StringBuilder();
if(negated) {
for (String command : commands) {
finalCommand.append(command);
}
}else if (isPowerOfTwo || isPowerOfTwoMinusOne){
if(isPowerOfTwoMinusOne)
finalCommand.append("L");
for(int i = 1; i < commands.size(); i++) {
finalCommand.append("R");
}
}else {
//Mirroring here
for(int i = commands.size() - 1; i >= 0; i--) {
finalCommand.append(commands.get(i));
}
}
return finalCommand.toString();
}
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) );
}
}
这是一种等效于@tevemadar的解决方案的解决方案,尽管使用的是Java。
public class CommandBuilderTwo {
private static String buildCommand(int N) {
if(N == 0 || 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) );
}
}
答案 4 :(得分:0)
是的,我也完全同意自己的看法,并发现我的提示很有用(好的,答案已经消失了)。
如果不需要验证,则生成步骤非常简单:
function getSequence(n){
if(n==0 || n==1)return "";
var steps=n<0?["R","L"]:["L","R"];
return (n<0?-n:n-1).toString(2) // get binary number
.replace(/0/g,steps[0]).replace(/1/g,steps[1]) // replace digits with L/R
.split('').reverse().join(''); // reverse order
}
for(var i=-20;i<=20;i++)
console.log(i,getSequence(i));
.as-console-wrapper { max-height: 100% !important; top: 0; }