【问题标题】:generate 7 digits生成 7 位数字
【发布时间】:2015-08-03 01:07:01
【问题描述】:

给定一个电话键盘,如下图:

1 2 3
4 5 6
7 8 9
  0

到目前为止,我有这个... 我已经从起始位置计算了所有可能的移动并填充了一个名为MoveArray 的数组以帮助记忆我正在存储调用(即printoutArr)。

我正在尝试递归构建 7 个字母的字符串,但我没有得到任何地方。这就是我卡住的地方。对此有任何帮助吗?!?!

【问题讨论】:

  • 这是一个难题。您打算使用 BFS 还是 DFS?您打算如何跟踪重复的移动和循环?
  • 检查 && this.printoutArr[startingPos][i]==false 我将标志设置为 true,因此不会再次生成数字。

标签: java stringbuilder memoization


【解决方案1】:

我在这个答案中使用了 Java 8。如果你想让我隐瞒不使用流,请告诉我。

我建议将问题分成两部分。第一个是定义每个棋子可能移动的算法,第二个是获得所有组合的递归。

第一个问题,从一个界面开始:

public interface MoveGenerator {
    IntStream nextPositions(Integer position);
}

您可以只使用Function<Integer,IntStream>,但定义您自己的界面会让事情变得更加明显。

然后,您可以为每个部分定义此接口的实现。一旦你定义了合法移动的数组,这就很简单了。有关不需要数组的更优雅的解决方案,请参阅下面的附录。

int[][] legalBishopMoves = {{7, 9}, {5, 9}, {4, 6}, {5, 7}...};
MoveGenerator bishopMoves = pos -> Arrays.stream(legalBishopMoves[pos]);

第二个问题其实比较简单。它需要一个起始位置和一个MoveGenerator,并使用递归来生成所有字符串:

void getCombinations(String combination, int position, MoveGenerator generator) {
    if (combination.length() == 7) {
        System.out.println(combination);
    } else {
        generator.nextPositions(position)
            .forEach(pos -> getCombinations(combination + pos, pos, generator);
    }
}

你可以这样称呼getCombinations("", 4, bishopMoves)

附录

我并不特别喜欢在我的代码中使用静态数组来表示规则,因此我创建了一个替代方案,它根据每个部分的基本规则生成移动:

int col(int pos) {
    return pos == 0 ? 1 : (pos - 1) % 3;
}

int row(int pos) {
    return pos == 0 ? 2 : (pos - 1) / 3;
}

int rows(int from, int to) {
    return Math.abs(row(from) - row(to));
}

int cols(int from, int to) {
    return Math.abs(col(from) - col(to));
}

interface MoveTest {
    boolean isLegal(int rows, int cols);
}

MoveGenerator fromTest(MoveTest test) {
    return from -> IntStream.range(0, 10)
        .filter(to -> from != to)
        .filter(to -> test.isLegal(rows(from, to), cols(from, to)));
}

MoveGenerator bishopMoves = fromTest((r, c) -> r == c);
MoveGenerator knightMoves = fromTest((r, c) -> r + c == 3);
MoveGenerator rookMoves = fromTest((r, c) -> r == 0 || c == 0);
MoveGenerator queenMoves = fromTest((r, c) -> r == 0 || c == 0 || r == c); 
MoveGenerator kingMoves = fromTest((r, c) -> r <= 1 && c <= 1);

这很好用,但我建议你不要尝试任何皇后动作,因为你最终会得到很多字符串!

我没有添加典当动作,因为它不会产生任何东西。

【讨论】:

    【解决方案2】:

    我喜欢@sprinter 的方式,因为它更简洁并且利用了 Java 8。 但这里有一个更详细的方法来解决这个枚举问题:

    首先定义一个描述棋子运动的通用接口

    interface Movement {
        int x();
        int y();
    }
    

    然后我们将使用一个枚举来实现其中一个片段的动作

    enum BishopMovement implements Movement {
        //the names for the enum constants
        //indicate the direction of the movement and how far it goes
        UpLeft1( -1, -1 ),
        UpLeft2( -2, -2 ),
        UpRight1( 1, -1 ),
        UpRight2( 2, -2 ),
        DownRight1( 1, 1 ),
        DownRight2( 2, 2 ),
        DownLeft1( -1, 1 ),
        DownLeft2( -2, 2 );
    
        final int x, y;
    
        BishopMovement( int xOffset, int yOffset ){
            x = xOffset;
            y = yOffset;
        }
    
        @Override
        public int x() {
            return x;
        }
    
        @Override
        public int y() {
            return y;
        }    
    }
    

    这是骑士的另一个例子

    enum KnightMovement implements Movement {
        //again, the names say which movement they represent
        UpLeft( -1, -2 ),
        UpRight( 1, -2 ),
        RightUp( 2, -1 ),
        RightDown( 2, 1 ),
        DownRight( 1, 2 ),
        DownLeft( -1, 2 ),
        LeftDown( -2, 1 ),
        LeftUp( -2, -1 );
    
        final int x, y;
    
        KnightMovement( int xOffset, int yOffset ){
            x = xOffset;
            y = yOffset;
        }
    
        @Override
        public int x() {
            return x;
        }
    
        @Override
        public int y() {
            return y;
        }
    }
    

    像这样定义每个部分有点乏味,但我确实喜欢将动作组织在一个枚举中。我想是个人喜好。

    我也将在一个枚举中定义键盘中的键

    enum Key {
        //note that the order is important here
        //because we'll be using ordinal() to easily
        //convert between an int and a Key
        Zero( 1, 3 ),
        One( 0, 0 ),
        Two( 1, 0 ),
        Three( 2, 0 ),
        Four( 0, 1 ),
        Five( 1, 1 ),
        Six( 2, 1 ),
        Seven( 0, 2 ),
        Eight( 1, 2 ),
        Nine( 2, 2 ),
        None( -1, -1 ); //default constant
    
        final int x, y;
    
        Key( int xOffset, int yOffset ){
            x = xOffset;
            y = yOffset;
        }
    
        //overriding toString because it'll be easier
        //to record the moves
        @Override
        public String toString() {
            String s = "";
            if( !this.equals( None ) )
                s += this.ordinal();
            return s;
        }
    }
    

    最后,解决方案

    public class Solution {    
        static Key[][] keypad;
        static final int x1 = 2, y1 = 3; //Key One will be at x=2, y=3
    
        static {
            keypad = new Key[7][10]; //extra padding
            for( int x = 0; x < 7; x++ ){
                for( int y = 0; y < 10; y++ ) {
                    keypad[x][y] = Key.None; //set all the elements to the default
                }
            }
            for( Key k : Key.values() ) {
                keypad[x1+k.x][y1+k.y] = k; //set all the keys
            }
        }
    
        public static void main( String[] args ) {
            int key = 1;
            int totalMoves = 7;
            String initialMovement = "-";
            String allPossibleMoves = recursiveSolve( key, totalMoves, initialMovement, BishopMovement.values() );
            //all the possible moves will be separated by spaces with a trailing space at the end
            System.out.print( allPossibleMoves );
        }
    
    
        static String recursiveSolve( int key, int movesLeft, String moves, Movement[] possibleMoves ) {
            String results="";
            if( movesLeft > 0 ){
                Key k = Key.values()[key], nextKey;
                for( Movement m : possibleMoves ){
                    nextKey = keypad[x1+k.x+m.x()][y1+k.y+m.y()];
                    if( !nextKey.equals( Key.None ) ) {
                        results += recursiveSolve( nextKey.ordinal(), movesLeft - 1, moves + nextKey, possibleMoves );
                    }
                }
            }
            else {
                results = moves+" ";
            }
            return results;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-08-09
      • 1970-01-01
      • 2014-04-06
      • 2014-04-08
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      • 1970-01-01
      • 2017-07-14
      相关资源
      最近更新 更多