当前位置: 面试刷题>> 分割字符串 (经典算法题500道)


题目描述补充

给定一个字符串s和一个整数k,你的任务是将字符串s分割成恰好k个非空子串,使得这些子串连接起来的结果与原始字符串相同,并且所有子串的字典序之和最小。字典序之和定义为将每个子串视为独立字符串并比较它们时的总排序结果。

示例

输入:

s = "abacba"
k = 4

输出:

["a", "ba", "c", "ba"]

解释:分割成["a", "ba", "c", "ba"]后,这四个子串的字典序之和最小。

注意

  • 分割的子串必须是连续的。
  • 分割后的子串数量必须等于k
  • 如果有多个解,返回任意一个即可。

PHP代码示例

function splitString($s, $k) {
    $n = strlen($s);
    $dp = array_fill(0, $n + 1, array_fill(0, $k + 1, PHP_INT_MAX));
    $prev = array_fill(0, $n + 1, array_fill(0, 26, ''));

    $dp[0][0] = 0;

    for ($i = 1; $i <= $n; $i++) {
        for ($j = 1; $j <= $k; $j++) {
            for ($x = $i - 1; $x >= $j - 1; $x--) {
                $substring = substr($s, $x, $i - $x);
                $cost = $dp[$x][$j - 1] + strcmp($substring, $prev[$x][$ord($substring[0]) - ord('a')]);
                if ($cost < $dp[$i][$j]) {
                    $dp[$i][$j] = $cost;
                    $prev[$i][ord($substring[0]) - ord('a')] = $substring;
                }
            }
        }
    }

    $result = [];
    $i = $n;
    $j = $k;
    while ($j > 0) {
        for ($x = $i - 1; $x >= $j - 1; $x--) {
            if ($dp[$i][$j] == $dp[$x][$j - 1] + strcmp(substr($s, $x, $i - $x), $prev[$x][ord(substr($s, $x, 1)[0]) - ord('a')])) {
                $result[] = substr($s, $x, $i - $x);
                $i = $x;
                $j--;
                break;
            }
        }
    }

    return array_reverse($result);
}

// 测试
echo json_encode(splitString("abacba", 4));

注意: 上述PHP代码示例是一个简化的思路框架,实际实现可能需要根据具体要求进行调整,特别是字典序比较和动态规划转移方程的部分。

Python代码示例

Python实现通常会更简洁,但考虑到篇幅和面试环境,这里不直接给出完整实现,而是描述一个大致的递归加记忆化搜索或动态规划的策略。

JavaScript代码示例

JavaScript代码也类似,但同样为了简洁性,这里仅描述方法:

  1. 使用动态规划或递归加记忆化来记录每个位置分割成不同数量子串的最小字典序之和。
  2. 通过比较不同分割点得到的子串的字典序来更新最小和。
  3. 回溯构造出最终的分割结果。

码小课 网站中有更多关于字符串处理、动态规划、递归等算法相关内容的分享,欢迎大家学习交流。

推荐面试题