You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

字符串按字母序排列的最短操作路径及序列输出技术问询

解决字符串排序最短操作序列问题

嘿,我明白你的问题了:你需要用仅有的两种操作——b(交换前两个字符)和s(整体右移一位)——找到把任意字符串排成字母顺序的最短操作序列,但现在你的StringBuilder会把所有尝试过的操作都追加进去,没法精准输出那条最短的路径。

问题本质拆解

其实这个问题就是典型的状态空间最短路径搜索:每个字符串都是一个状态,两种操作就是状态之间的“移动方式”,我们要从初始状态(输入字符串)走到目标状态(排序后的字符串),找步数最少的那条路。

你之前的实现之所以会记录所有操作,大概率是用了深度优先搜索(DFS)或者没做正确的路径回溯/分支管理——DFS会一条路走到黑,尝试所有可能的分支,自然会把所有操作都存下来。而**广度优先搜索(BFS)**才是解决这类最短路径问题的最优选择,因为它是按“步数”逐层遍历的,第一次碰到目标状态时,对应的路径就是最短的。

具体实现思路

我给你梳理下清晰的解决步骤:

  • 先确定目标状态:把输入字符串排序,得到我们最终要到达的那个有序字符串。
  • 用BFS队列管理状态:队列里的每个元素要存两个东西——当前的字符串状态,以及走到这个状态用的操作序列。
  • 用集合记录已访问状态:避免重复处理同一个字符串(不然会陷入循环,比如连续5次s又回到原字符串)。
  • 生成新状态并推进搜索:对队列里的每个状态,分别执行b和s操作,生成新的字符串:
    • 执行b:交换前两个字符,比如BECAD变EBCAD,操作序列加个b。
    • 执行s:把最后一个字符移到最前面,比如BECAD变DBECA,操作序列加个s。
  • 终止条件:一旦生成的新字符串等于目标状态,直接返回对应的操作序列——这就是最短路径。

代码示例(Java)

import java.util.*;

public class ShortestSortOps {
    public static String getShortestSequence(String input) {
        // 先搞定目标状态:排序后的字符串
        char[] targetArr = input.toCharArray();
        Arrays.sort(targetArr);
        String target = new String(targetArr);
        
        // BFS队列:每个元素存当前字符串和对应的操作序列
        Queue<Map.Entry<String, String>> queue = new LinkedList<>();
        queue.add(new AbstractMap.SimpleEntry<>(input, ""));
        
        // 记录已经处理过的字符串,防止循环
        Set<String> visited = new HashSet<>();
        visited.add(input);
        
        while (!queue.isEmpty()) {
            Map.Entry<String, String> current = queue.poll();
            String currentStr = current.getKey();
            String ops = current.getValue();
            
            // 找到目标了,直接返回操作序列
            if (currentStr.equals(target)) {
                return ops;
            }
            
            // 执行b操作:交换前两个字符
            if (currentStr.length() >= 2) {
                char[] bArr = currentStr.toCharArray();
                char temp = bArr[0];
                bArr[0] = bArr[1];
                bArr[1] = temp;
                String bNewStr = new String(bArr);
                if (!visited.contains(bNewStr)) {
                    visited.add(bNewStr);
                    queue.add(new AbstractMap.SimpleEntry<>(bNewStr, ops + "b"));
                }
            }
            
            // 执行s操作:整体右移一位(等价于最后一个字符移到开头)
            if (currentStr.length() > 0) {
                char lastChar = currentStr.charAt(currentStr.length() - 1);
                String sNewStr = lastChar + currentStr.substring(0, currentStr.length() - 1);
                if (!visited.contains(sNewStr)) {
                    visited.add(sNewStr);
                    queue.add(new AbstractMap.SimpleEntry<>(sNewStr, ops + "s"));
                }
            }
        }
        
        // 兜底:理论上输入都能通过操作排序,这里只是防止极端情况
        return "";
    }

    public static void main(String[] args) {
        String testInput = "BECAD";
        String result = getShortestSequence(testInput);
        System.out.println("最短操作序列:" + result); // 输出bsssbsb,步数7,和你预期的一致
    }
}

关键细节提醒

  • 为什么BFS能找最短路径:BFS是按步数分层遍历的,第一层是1步操作能到的所有状态,第二层是2步的,以此类推。所以第一次遇到目标状态时,对应的步数肯定是最少的,不用再往下搜了。
  • 访问集合的必要性:如果不记录已访问的字符串,队列会不断生成重复的状态,比如你连续执行5次s又回到原字符串,程序会无限循环下去。
  • 边界情况处理:当字符串长度小于2时,b操作没意义,直接跳过就行;空字符串的情况你大概率不会遇到,但代码里也做了处理。

用这个思路改完之后,就不会再有StringBuilder乱追加操作的问题了——BFS只记录到达每个状态的最短路径,一旦找到目标就立刻返回,不会去遍历那些多余的分支。

内容的提问来源于stack exchange,提问作者xxFlashxx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:35:04