Java到1的最短路径

Java到1的最短路径,java,Java,旧程序 public class JavaApplication7 { public static void main(String[] args) { String n = ""; // any given whole positive integer long solution = 0; double t = Double.parseDouble(n); double pow = nearpow(t);

旧程序

public class JavaApplication7 {
    public static void main(String[] args) {
        String n = ""; // any given whole positive integer
        long solution = 0;
        double t = Double.parseDouble(n);
        double pow = nearpow(t);
        double nearpow = Math.pow(2, nearpow(t));
        double difference = Math.abs(t-nearpow);
        while(t!=1){
            if(t==nearpow){
                solution+=pow;
                t/=nearpow;
            }
            if(nearpow<t&&t!=1){
                t = t - difference;                 
                solution+=difference;
                t = t / nearpow;
                solution+=pow;                
            }
            else if(nearpow>t&&t!=1){
                t+=difference;                
                solution+=difference;      
                t/=nearpow;
                solution+=pow;
                }
            }
        System.out.println(solution);
    } 
    public static double nearpow(double t){
        double log = Math.log(t) / Math.log(2);

        long roundLog = Math.round(log);
        double dec = Math.abs(log-roundLog);
        long lowPow = (long)(log-dec);
        long highPow = lowPow+1;
        if(Math.abs(t-Math.pow(2,highPow))<Math.abs(t-Math.pow(2,lowPow))){
            return highPow;
        }
        else{
            return lowPow;
        }
    }
}
    String n = "54123";
    BigInteger t = new BigInteger(n);
    BigInteger one = new BigInteger("1");
    System.out.println(t);
    int solution =0;       
    while(!t.equals(one)){
        if(((t.and(one)).equals(BigInteger.ZERO))){
            System.out.println(t+"/2 =");
            t=t.shiftRight(1);
            solution++;  
            }
        else if((t.and(one)).equals(BigInteger.ONE)&&(((t.shiftRight(1).and(one))).equals(BigInteger.ONE))&&(((t.shiftRight(2).and(one))).equals(BigInteger.ONE))){
            System.out.println(t+"+2 =");
            t=t.add(one);
            solution++;

        }
        else if(t.and(one).shiftRight(1).equals(BigInteger.ZERO)&&t.and(one).equals(one)){
            System.out.println(t+"-1 =");
            t=t.subtract(one);            
            solution++;
        }
    }
    System.out.print(solution);
我是位运算的新手,所以我需要一些帮助来找出问题的新缺点,因为我写的东西对我来说还是很新的,为了增加位运算的新用途,我必须用BigInteger来写,这些术语我很难理解,然而,对于我使用的术语,它应该可以工作,但我找不到一个不工作的原因,以前使用的示例是762,它给出了259个操作,而对于新程序,它给出了15个操作,由于术语的新颖性,我仍然难以识别故障。 我写的解决方案(作品)


这是一个位操作的问题,正如除以2规则所暗示的那样

让我们看一看注释中提到的编号
762
(基数10),即
1011111010
(基数2)(现已删除)

除以2意味着将位向右移位。假设不允许这样做,除非数字可以被2整除,即最右边的位是0

所以,如果我们能右转,我们就能做到。如果不是,我们可以减去1来清除位

但是,如果下一位也为1,我们可以改为添加1,因此在一次操作中将多个1位翻转为0,例如
100111+1=101000

作为一项特殊考虑,
11
不应添加
1
,因为这将是
11
→ <代码>100→ <代码>10→ <代码>1,即3次操作。而是减去
1
得到
11
→ <代码>10→ <代码>1

1011111010
1:  /2 =  101111101
2:  -1 =  101111100
3:  /2 =   10111110
4:  /2 =    1011111
5:  +1 =    1100000
6:  /2 =     110000
7:  /2 =      11000
8:  /2 =       1100
9:  /2 =        110
10:  /2 =         11
11:  -1 =         10
12:  /2 =          1
12操作中找到解决方案


现在您只需要为它编写代码。

这是一个位操作的问题,正如除以2规则所暗示的那样

让我们看一看注释中提到的编号
762
(基数10),即
1011111010
(基数2)(现已删除)

除以2意味着将位向右移位。假设不允许这样做,除非数字可以被2整除,即最右边的位是0

所以,如果我们能右转,我们就能做到。如果不是,我们可以减去1来清除位

但是,如果下一位也为1,我们可以改为添加1,因此在一次操作中将多个1位翻转为0,例如
100111+1=101000

作为一项特殊考虑,
11
不应添加
1
,因为这将是
11
→ <代码>100→ <代码>10→ <代码>1,即3次操作。而是减去
1
得到
11
→ <代码>10→ <代码>1

1011111010
1:  /2 =  101111101
2:  -1 =  101111100
3:  /2 =   10111110
4:  /2 =    1011111
5:  +1 =    1100000
6:  /2 =     110000
7:  /2 =      11000
8:  /2 =       1100
9:  /2 =        110
10:  /2 =         11
11:  -1 =         10
12:  /2 =          1
12操作中找到解决方案

现在您只需为它编写代码。

表达式

        (!((t.and(one)).shiftRight(1)).equals(BigInteger.ZERO))

你错了。他们的目的是测试
t
的第二和第三个最低有效位是否为非零,但他们没有。它们每次只返回
false

这两个表达式都以
t和(one)
开头,这将隔离
t
的最后一位,而不是倒数第二位或倒数第三位。然后,每一位都将该位移开,实际上留下了
biginger.ZERO
。因此,这两个测试都归结为
biginger.ZERO.equals(biginger.ZERO)
,因为
biginger.ZERO
永远不等于
biginger.ZERO
,所以无论
t
是什么,结果都是一致的
false

你想要的是

        (!((t.shiftRight(1)).and(one)).equals(BigInteger.ZERO))

执行移位操作时,首先将所需的
t
位移动到
之前新的
BigInteger
中的最后一个位置,然后(一个)
将其隔离以进行测试。现在您实际上正在测试表达式的倒数第二位和倒数第三位

        (!((t.and(one)).shiftRight(1)).equals(BigInteger.ZERO))

你错了。他们的目的是测试
t
的第二和第三个最低有效位是否为非零,但他们没有。它们每次只返回
false

这两个表达式都以
t和(one)
开头,这将隔离
t
的最后一位,而不是倒数第二位或倒数第三位。然后,每一位都将该位移开,实际上留下了
biginger.ZERO
。因此,这两个测试都归结为
biginger.ZERO.equals(biginger.ZERO)
,因为
biginger.ZERO
永远不等于
biginger.ZERO
,所以无论
t
是什么,结果都是一致的
false

你想要的是

        (!((t.shiftRight(1)).and(one)).equals(BigInteger.ZERO))


执行移位操作时,首先将所需的
t
位移动到
之前新的
BigInteger
中的最后一个位置,然后(一个)
将其隔离以进行测试。现在您实际上正在测试
t
的倒数第二位和倒数第三位。我编写了@Andreas按位方法的版本

public static enum Op
{
    PLUS_1, MINUS_1, DIV_2
}
public static void shortest( final long value, final List<Op> steps )
{
    System.out.println( Long.toBinaryString( value ) );
    if ( value > 1L )
    {
        if ( ( value & 1L ) == 0L )
        {
            // last bit is 0
            steps.add( Op.DIV_2 );
            shortest( value / 2L, steps );
        }
        else if ( Long.highestOneBit( value ) == Long.bitCount( value ) )
        {
            // only 1 bits
            steps.add( Op.MINUS_1 );
            shortest( value - 1L, steps );
        }
        else if ( ( value & 3L ) == 3L )
        {
            // last bits are 11
            steps.add( Op.PLUS_1 );
            shortest( value + 1L, steps );
        }
        else
        {
            // last bits are 01
            steps.add( Op.MINUS_1 );
            shortest( value - 1L, steps );
        }
    }
}
public static void print( final long value, final List<Op> steps )
{
    System.out.printf( "%d = %<x = %s = %d %s\n", value, Long.toBinaryString( value ),
                       steps.size(), steps );
}
public static void main( final String[] args )
{
    final List<Op> steps = new ArrayList<>();
    shortest( 726, steps );
    print( 726, steps );

    steps.clear();
    shortest( 762, steps );
    print( 762, steps );
}

我编写了@Andreas按位方法的版本

public static enum Op
{
    PLUS_1, MINUS_1, DIV_2
}
public static void shortest( final long value, final List<Op> steps )
{
    System.out.println( Long.toBinaryString( value ) );
    if ( value > 1L )
    {
        if ( ( value & 1L ) == 0L )
        {
            // last bit is 0
            steps.add( Op.DIV_2 );
            shortest( value / 2L, steps );
        }
        else if ( Long.highestOneBit( value ) == Long.bitCount( value ) )
        {
            // only 1 bits
            steps.add( Op.MINUS_1 );
            shortest( value - 1L, steps );
        }
        else if ( ( value & 3L ) == 3L )
        {
            // last bits are 11
            steps.add( Op.PLUS_1 );
            shortest( value + 1L, steps );
        }
        else
        {
            // last bits are 01
            steps.add( Op.MINUS_1 );
            shortest( value - 1L, steps );
        }
    }
}
public static void print( final long value, final List<Op> steps )
{
    System.out.printf( "%d = %<x = %s = %d %s\n", value, Long.toBinaryString( value ),
                       steps.size(), steps );
}
public static void main( final String[] args )
{
    final List<Op> steps = new ArrayList<>();
    shortest( 726, steps );
    print( 726, steps );

    steps.clear();
    shortest( 762, steps );
    print( 762, steps );
}

它是如何失败的?举一个具体的例子。你知道失败的确切临界值吗?将所有相关信息编辑到你的问题中,使其完整。顺便说一句,我想从我的@s$中猜出最小值是
k+(n-2^k)
其中
n
是你的数字,
k=floor(log2(n))
k
是除以2的除数,而
n-2^k
是数字离电源有多远
1011010110
101101011
101101100
10110110
1011011
1011100
101110
10111
11000
1100
110
11
10
1
726 = 2d6 = 1011010110 = 13 [DIV_2, PLUS_1, DIV_2, DIV_2, PLUS_1, DIV_2, DIV_2, PLUS_1, DIV_2, DIV_2, DIV_2, MINUS_1, DIV_2]
1011111010
101111101
101111100
10111110
1011111
1100000
110000
11000
1100
110
11
10
1
762 = 2fa = 1011111010 = 12 [DIV_2, MINUS_1, DIV_2, DIV_2, PLUS_1, DIV_2, DIV_2, DIV_2, DIV_2, DIV_2, MINUS_1, DIV_2]