通过迭代按字母顺序排列字符串

时间:2018-02-04 19:38:53

标签: java string sorting recursion minimum

我想我已经设法找到按字母顺序排列字符串(ABCDE的任意顺序)的最小移动量。

必须遵循一些条件:

  • 交换第一个和第二个元素(b)或:
  • 将字符串向右移动一步(s

然而,我也试图打印出我用来走最短路径的动作。
例如,如果我放入BECAD,我会得到Minimum step used: 7但我还要打印bsssbsb

现在我的StringBuilder会继续追加所有可能的动作。任何帮助,将不胜感激。

  public static void main(String[] args) {
        String s = "BECAD";
        int step = 0;
        System.out.println("Minimum step used: " + robot(s, step));
    }

    public static int robot(String s, int step) {

        StringBuilder sb1 = new StringBuilder();
        Queue<State> leftQ = new LinkedList<>();
        Queue<State> rightQ = new LinkedList<>();
        State nodeLeft = new State(s, step, 0, sb1);
        State nodeRight = new State(s, step, 0, sb1);
//while we havent reached ABCDE continue until one of them reaches
        while(!(nodeLeft.s.equals("ABCDE")) && !(nodeRight.s.equals("ABCDE"))) {
// first loop we will always enter the first condition.
            if(nodeLeft.previousMove == 0 || nodeRight.previousMove == 0) {
                leftQ.offer(new State(nodeLeft.s.substring(1, 2) + nodeLeft.s.substring(0, 1) + nodeLeft.s.substring(2, 5), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 1, nodeLeft.allMoves.append("b")));
                rightQ.offer(new State(nodeLeft.s.substring(4, 5) + nodeLeft.s.substring(0, 4), nodeRight.currentSteps + 1, nodeRight.previousMove + 2, nodeRight.allMoves.append("s"))); 
// there are two queues, left and right. first we swap the 1st element with the 2nd element and push it to the leftQ. The other one be will shift the string one step left and push it to the rightQ.
            } else if(nodeLeft.previousMove == 1 || nodeRight.previousMove == 1) {
                leftQ.offer(new State(nodeLeft.s.substring(4, 5) + nodeLeft.s.substring(0, 4), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 2, nodeLeft.allMoves.append("s")));
                rightQ.offer(new State(nodeRight.s.substring(4, 5) + nodeRight.s.substring(0, 4), nodeRight.currentSteps + 1, nodeRight.previousMove = 2, nodeRight.allMoves.append("s")));
            } else if(nodeLeft.previousMove == 2 || nodeRight.previousMove == 2) {
                leftQ.offer(new State(nodeLeft.s.substring(1, 2) + nodeLeft.s.substring(0, 1) + nodeLeft.s.substring(2, 5), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 1, nodeLeft.allMoves.append("b")));
                leftQ.offer(new State(nodeLeft.s.substring(4, 5) + nodeLeft.s.substring(0, 4), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 2, nodeLeft.allMoves.append("s")));
                rightQ.offer(new State(nodeRight.s.substring(1, 2) + nodeRight.s.substring(0, 1) + nodeRight.s.substring(2, 5), nodeRight.currentSteps + 1, nodeRight.previousMove = 1, nodeRight.allMoves.append("b")));
                rightQ.offer(new State(nodeRight.s.substring(4, 5) + nodeRight.s.substring(0, 4), nodeRight.currentSteps + 1, nodeRight.previousMove = 2, nodeRight.allMoves.append("s")));
// to avoid endless loop i check the previous move. If i swapped previously i must shift one step left.
            }
            nodeLeft = leftQ.poll();
            nodeRight = rightQ.poll();
// i continue to poll from both the queues to see which one reaches ABCDE first. 
// Since i am building something like a binary tree on the width
// eventually one of the nodes will reach first. Then i set the other to a max value since it never finished it search.
        }

        if(!(nodeLeft.s.equals("ABCDE"))) {
            nodeLeft.currentSteps = Integer.MAX_VALUE;
        }
        if(!(nodeRight.s.equals("ABCDE"))) {
            nodeRight.currentSteps = Integer.MAX_VALUE;
        }
        return  Math.min(nodeLeft.currentSteps, nodeRight.currentSteps);
// here i return the minimum amount of steps taken to achieve my goal
    }


public class State {

    public String s;
    public int currentSteps;
    public int previousMove;
    public StringBuilder allMoves;

    public State(String s, int currentSteps, int previousMove, StringBuilder allMoves) {
        this.s = s;
        this.currentSteps = currentSteps;
        this.previousMove = previousMove;
        this.allMoves = allMoves;
    }

}

1 个答案:

答案 0 :(得分:0)

您的代码有两个主要问题导致您感到悲伤。

首先, 您将相同的字符串生成器传递给左侧和右侧节点。这意味着左侧节点上发生的任何追加操作也会发生在右侧。

StringBuilder sb1 = new StringBuilder();
Queue<State> leftQ = new LinkedList<>();
Queue<State> rightQ = new LinkedList<>();
State nodeLeft = new State(s, step, 0, sb1);
State nodeRight = new State(s, step, 0, sb1);

这是一个简单的修复,你只需要制作两个StringBuilders,例如

StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
State nodeLeft = new State(s, step, 0, sb1);
State nodeRight = new State(s, step, 0, sb2);

第二个问题是,对于每个节点,如果是块

,你实际上会在你的第二个节点中两次附加到同一个Stringbuilder
leftQ.offer(new State(nodeLeft.s.substring(1, 2) + nodeLeft.s.substring(0, 1) + nodeLeft.s.substring(2, 5), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 1, nodeLeft.allMoves.append("b")));
leftQ.offer(new State(nodeLeft.s.substring(4, 5) + nodeLeft.s.substring(0, 4), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 2, nodeLeft.allMoves.append("s")));

rightQ.offer(new State(nodeRight.s.substring(1, 2) + nodeRight.s.substring(0, 1) + nodeRight.s.substring(2, 5), nodeRight.currentSteps + 1, nodeRight.previousMove = 1, nodeRight.allMoves.append("b")));
rightQ.offer(new State(nodeRight.s.substring(4, 5) + nodeRight.s.substring(0, 4), nodeRight.currentSteps + 1, nodeRight.previousMove = 2, nodeRight.allMoves.append("s")));

快速解决方法是为您创建的其中一个节点创建一个StringBuilder,并将现有节点传递给另一个节点,例如。

leftQ.offer(new State(nodeLeft.s.substring(1, 2) + nodeLeft.s.substring(0, 1) + nodeLeft.s.substring(2, 5), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 1, new StringBuilder(nodeLeft.allMoves).append("b")));
leftQ.offer(new State(nodeLeft.s.substring(4, 5) + nodeLeft.s.substring(0, 4), nodeLeft.currentSteps + 1, nodeLeft.previousMove = 2, nodeLeft.allMoves.append("s")));