解题思路

这是一道字符串压缩编码问题,主要思路如下:

  1. 问题分析:

    • 编码规则为 ,表示重复
    • 需要递归处理子串,实现嵌套编码
    • 需要考虑所有可能的分割方式
    • 选择能得到最短结果的编码方式
  2. 解决方案:

    • 递归处理字符串
    • 遍历所有可能的重复子串长度
    • 对每个长度寻找最优的重复次数
    • 将字符串分为前缀、重复部分、后缀三部分
    • 递归处理这三部分
  3. 优化策略:

    • 从最长的可能重复长度开始尝试
    • 提前剪枝无效的压缩情况
    • 递归处理子串实现嵌套压缩

代码

#include <bits/stdc++.h>
using namespace std;

string encoding_string(string s) {
    if (s == "") return "";
    if (s.size() <= 4) return s;
    
    int len = s.size();
    int len2 = len / 2;    // 重复子串的最大长度
    
    int best_count = 0;    // 最优重复次数
    int best_len = INT_MAX;// 最优压缩长度
    string pre, cur, lat;  // 前缀、重复串、后缀
    
    while (len2 >= 1) {
        for (int k = 0; k <= len - len2; k++) {
            int count = 1;
            string s2 = s.substr(k, len2);
            
            // 计算重复次数
            for (int j = 1; len2 * j + len2 <= len; j++) {
                string s3 = s.substr(k + len2 * j, len2);
                if (s2.compare(s3) == 0)
                    count++;
                else
                    break;
            }
            
            // 计算压缩后长度
            int newlen = (len - count * len2) + 3 + len2;
            if (newlen < len && newlen < best_len && count > 1) {
                best_len = newlen;
                best_count = count;
                pre = s.substr(0, k);
                cur = s.substr(k, len2);
                lat = s.substr(k + count * len2);
            }
        }
        len2--;
    }
    
    if (best_count == 0)
        return s;
        
    // 递归处理三个部分
    return encoding_string(pre) + 
           to_string(best_count) + "[" + 
           encoding_string(cur) + "]" + 
           encoding_string(lat);
}

int main() {
    string s;
    cin >> s;
    cout << encoding_string(s).size() << endl;
    return 0;
}
import java.io.BufferedReader;
import java.io.InputStreamReader;

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
        br.close();
        System.out.println(solution(s).length());
    }

    private static String solution(String s) {
        if (s.length() <= 4) return s;
        int len = s.length();
        int rptLen = len >> 1; // 当前尝试的重复的长度
        int bestRptTime = 0;
        int bestCompressLen = len;
        String seg1 = "", seg2 = "", seg3 = "";
        while (rptLen >= 1) {
            for (int k = 0; k <= len - (rptLen << 1); k++) { // 从k位置开始寻找,至少留两段
                int count = 1;
                String s2 = s.substring(k, k + rptLen);
                for (int j = 1; k + j * rptLen + rptLen <= len; j++) { // 判断最多重复几次
                    String s3 = s.substring(k + j * rptLen, k + (j + 1) * rptLen);
                    if (s2.equals(s3)) count++;
                    else break;
                }
                int newLen = len - count * rptLen + 3 + rptLen;
                if (newLen < len && newLen < bestCompressLen) { // 新长度合适
                    bestCompressLen = newLen;
                    bestRptTime = count;
                    seg1 = s.substring(0, k);
                    seg2 = s.substring(k, k + rptLen);
                    seg3 = s.substring(k + count * rptLen);
                }
            }
            rptLen--;
        }
        if (bestRptTime == 0) return s;
        return solution(seg1) + bestRptTime + "[" + solution(seg2) + "]" + solution(seg3);
    }
}
def encoding_string(s: str) -> str:
    if not s: return ""
    if len(s) <= 4: return s
    
    length = len(s)
    len2 = length // 2
    
    best_count = 0
    best_len = float('inf')
    pre = cur = lat = ""
    
    while len2 >= 1:
        for k in range(length - len2 + 1):
            count = 1
            s2 = s[k:k+len2]
            
            j = 1
            while len2 * j + len2 <= length:
                s3 = s[k+len2*j:k+len2*j+len2]
                if s2 == s3:
                    count += 1
                else:
                    break
                j += 1
            
            newlen = (length - count * len2) + 3 + len2
            if newlen < length and newlen < best_len and count > 1:
                best_len = newlen
                best_count = count
                pre = s[:k]
                cur = s[k:k+len2]
                lat = s[k+count*len2:]
        
        len2 -= 1
    
    if best_count == 0:
        return s
        
    return encoding_string(pre) + \
           str(best_count) + "[" + \
           encoding_string(cur) + "]" + \
           encoding_string(lat)

def main():
    s = input().strip()
    print(len(encoding_string(s)))

if __name__ == "__main__":
    main()

算法及复杂度

  • 算法:递归 + 贪心
  • 时间复杂度: - 为字符串长度
  • 空间复杂度: - 递归调用栈的深度