hiho一下 第160周 压缩字符串

来源:互联网 发布:分镜头制作软件 编辑:程序博客网 时间:2024/06/15 13:48

题目1 : 压缩字符串

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi希望压缩一个只包含大写字母'A'-'Z'的字符串。他使用的方法是:如果某个子串 S 连续出现了 X 次,就用'X(S)'来表示。例如AAAAAAAAAABABABCCD可以用10(A)2(BA)B2(C)D表示。

此外,这种压缩方法是可以嵌套的,例如HIHOHIHOCODERHIHOHIHOCODER可以表示成2(2(HIHO)CODER)。

对于一个字符串 S ,合法的压缩表示可能有很多种。例如AAAAAAAAAABABABCCD还可以表示成9(A)3(AB)CCD。小Hi希望知道其中最短的表示方法长度是多少。

输入

第一行一个正整数 T (1 ≤ T ≤ 10),表示测试数据的组数。

以下 T 行每行一个字符串 S ,长度不超过100。

输出

对于每组数据,输出最短的表示方法的长度。

样例输入
3ABCAAAAAAAAAABABABCCDHIHOHIHOCODERHIHOHIHOCODER
样例输出
31215
思路参考了:  https://hihocoder.com/discuss/question/4635

本题是一道非常经典的动态规划题目。

设S[1..n]是一个长度为n的字符串,best(S)是S的最短压缩,那么best(S)可能为三种形式中最短的一种:

1) 原串形式:best(S) = S。例如CCD最短压缩就是CCD本身。

2) 拼接形式: best(S[1..n]) = best(S[1..i]) + best(S[i+1..n])。

例如AAAAAAAAAABABABCCD的最短压缩9(A)3(AB)CCD,可以视为由best(AAAAAAAAAABABAB) = 9(A)3(AB) 和 best(CCD) = CCD 拼接而成。

3) 嵌套形式: best(S[1..n]) = k的位数 + 2 + best(S[1..n/k]),其中k>1且是n的约数,S是由k个S[1..n/k]循环拼接而成。

也就是说S[1..n]可以表示成k(s[1..n/k]),这时k(s[1..n/k])的长度是k的位数 + 一对括号的长度2 + best(S[1..n/k)

例如HIHOHIHOCODERHIHOHIHOCODER有循环节HIHOHIHOCODER,所以best(HIHOHIHOCODERHIHOHIHOCODER) = 1 + 2 + (best(HIHOHIHOCODER))。

package hihocoder;import java.util.*;//https://hihocoder.com/problemset/problem/1320?sid=1142210public class yasuozifuchuan {public static void main(String[] args) {// TODO Auto-generated method stubScanner sc=new Scanner(System.in);int n=sc.nextInt();sc.nextLine();for(int i=0;i<n;i++){String s=sc.nextLine();helper(s);}}private static void helper(String s){int n=s.length();int[][] dp=new int[n][n];for(int i=0;i<n;i++){for(int j=i;j<n;j++)dp[i][j]=j-i+1;}for(int stride=1;stride<n;stride++){for(int i=0;i+stride<n;i++){for(int j=0;j<stride;j++){dp[i][i+stride]=Math.min(dp[i][i+stride],dp[i][i+j]+dp[i+j+1][i+stride]);int cnt=contains(s,i,j+1,stride+1);if(cnt>0){dp[i][i+stride]=Math.min(dp[i][i+stride], get(cnt)+2+dp[i][i+j]);}}}}System.out.println(dp[0][n-1]);}//判断能否模块化private static int contains(String s,int start,int partlen,int len){if(len<partlen)return -1;if(len%partlen!=0)return -1;for(int i=0;i<len;i++){if(s.charAt(start+i)!=s.charAt(start+(i%partlen)))return -1;}return len/partlen;}//模块化前面的数字位数private static int get(int data){int res=0;while(data>0){data/=10;res++;}return res;}}