Java 平方子序列
问题-如果一个字符串可以通过连接同一字符串的两个副本获得,则该字符串称为方形字符串。例如,“abab”、“aa”是方字符串,“aaa”、“abba”不是。给定一个字符串,该字符串有多少子序列是方字符串?可以通过从字符串中删除零个或多个字符并保持其余字符的相对顺序来获得字符串的子序列 输入格式 第一行包含测试用例的数量T。 T测试用例如下。每个大小写包含一个字符串S 输出格式 输出T行,每个测试用例一行,包含要求的答案模100000007 限制条件: 1.≤T≤20 S最多有200个小写字符('a'-'z') 样本输入Java 平方子序列,java,string,recursion,Java,String,Recursion,问题-如果一个字符串可以通过连接同一字符串的两个副本获得,则该字符串称为方形字符串。例如,“abab”、“aa”是方字符串,“aaa”、“abba”不是。给定一个字符串,该字符串有多少子序列是方字符串?可以通过从字符串中删除零个或多个字符并保持其余字符的相对顺序来获得字符串的子序列 输入格式 第一行包含测试用例的数量T。 T测试用例如下。每个大小写包含一个字符串S 输出格式 输出T行,每个测试用例一行,包含要求的答案模100000007 限制条件: 1.≤T≤20 S最多有200个小写字符('a
3
aaa
abab
baaba
样本输出
3
3
6
我的代码只通过了2个测试用例,因为大型字符串的递归需要4秒以上才能生成答案,所以测试用例并没有通过
我最初打算导出所有可能的子序列,然后我将检查导出的子序列是否为平方子序列
有谁能给我一个更好的方法来解决这个问题,而不需要生成子序列
import java.io.*;
import java.util.*;
public class Subsequence {
static int count;
public static void print(String prefix, String remaining, int k) {
if (k == 0) {
//System.out.println(prefix);
if(prefix.length() %2 == 0 && check(prefix) != 0 && prefix.length() != 0)
{
count++;
//System.out.println(prefix);
}
return;
}
if (remaining.length() == 0)
return;
print(prefix + remaining.charAt(0), remaining.substring(1), k-1);
print(prefix, remaining.substring(1), k);
}
public static void main(String[] args)
{
//String s = "aaa";
Scanner sc = new Scanner(System.in);
int t=Integer.parseInt(sc.nextLine());
while((t--)>0)
{
count = 0;
String s = sc.nextLine();
for(int i=0;i<=s.length();i++)
{
print("",s,i);
}
System.out.println(count);
}
}
public static int check(String s)
{
int i=0,j=(s.length())/2;
for(;i<(s.length())/2 && j < (s.length());i++,j++)
{
if(s.charAt(i)==s.charAt(j))
{
continue;
}
else
return 0;
}
return 1;
}
}
import java.io.*;
导入java.util.*;
公共类子序列{
静态整数计数;
公共静态无效打印(字符串前缀、剩余字符串、int k){
如果(k==0){
//System.out.println(前缀);
如果(prefix.length()%2==0&&check(prefix)!=0&&prefix.length()!=0)
{
计数++;
//System.out.println(前缀);
}
返回;
}
if(剩余.length()==0)
返回;
打印(前缀+剩余字符(0),剩余子字符串(1),k-1);
打印(前缀,剩余。子字符串(1),k);
}
公共静态void main(字符串[]args)
{
//字符串s=“aaa”;
扫描仪sc=新的扫描仪(System.in);
int t=Integer.parseInt(sc.nextLine());
而((t--)>0)
{
计数=0;
字符串s=sc.nextLine();
对于(int i=0;i基本思想:我们可以将从给定输入字符串派生的所有平方序列排列成一个树状图-基本上允许将多棵树合并成一个或多个父树。这些树中的每棵树都有一个(局部)最长可能的平方序列作为根,叶都是长度为2的平方子序列,可以从根序列派生。现在找到所有可能的子序列的最简单方法是以任何给定的方式遍历此树并计算节点。因为(本地)很难找到对于给定的输入,我们使用另一个选项:从叶子开始,遍历到最长的序列。
只要搜索长度为2的所有可能的平方序列,就可以很容易地找到这些序列
平方序列之间的关系示例如下:
input: agbhbeiauzbib
longest sequences: abbabb and abiabi
childsequences of abbabb:
2x abab
bbbb
these sequences would have subsequences themselves of length 2
现在从理论到实践:
由于输入字符串中字符的位置与两个不同的序列相关(input:“aaa”序列:01->“aa”02->“aa”
我们可以将这些序列区分开来,尽管它们产生相同的字符串),因此子序列可以表示为List
现在开始第一步:找到所有可能的长度为2的平方子序列:基本上我们需要做的就是找到长度为2的索引的所有置换,这样索引就指向输入字符串中的等效字符
private static List<List<Integer>> listDoubleSequences(String in)
{
List<List<Integer>> result = new ArrayList<>();
//map all characters to their indices in the inputstring
HashMap<Character , List<Integer>> posMap = new HashMap<>();
for(int i = 0 ; i < in.length() ; i++)
{
char c = in.charAt(i);
if(posMap.get(c) == null)
posMap.put(c , new ArrayList<>());
posMap.get(c).add(i);
}
System.out.println(posMap);
posMap.values().forEach(indices -> {
//find all possible permutations with length 2
for (int i = 0; i < indices.size(); i++)
for (int j = i + 1; j < indices.size(); j++) {
List<Integer> seq = new ArrayList<>();
seq.add(indices.get(i));
seq.add(indices.get(j));
result.add(seq);
}
});
System.out.println("Found double sequences:");
result.forEach(l -> printSeq(in, l));
return result;
}
由于任何长度为2
的有效子序列都包含许多长度为length==2
的平方序列,因此我们可以通过简单地查找长度为2
的平方序列的所有可能组合来确保找到所有可能的平方序列
public static void sqrSubseqCount(String in)
{
List<List<Integer>> len_2_seq = listDoubleSequences(in);
List<List<Integer>> prev_round = new ArrayList<>(len_2_seq);
final Set<List<Integer>> next_round = new HashSet<>();
int count = len_2_seq.size();
System.out.println();
System.out.println("Searching longer sequences:");
while(!prev_round.isEmpty())
{
next_round.clear();
prev_round.forEach(l -> len_2_seq.forEach(l2 -> {
List<Integer> merge = merge(l , l2);
if(merge != null && !next_round.contains(merge))
{
next_round.add(merge);
printSeq(in , merge);
}
}));
count += next_round.size();
prev_round.clear();
prev_round.addAll(next_round);
}
System.out.println();
System.out.println("Total sequences found: " + count + " in: " + in);
}
publicstaticvoidsqrsubseqcount(字符串输入)
{
列表len_2_seq=列表双序列(in);
上一轮列表=新阵列列表(列2顺序);
下一轮的最终集=新哈希集();
int count=len_2_seq.size();
System.out.println();
System.out.println(“搜索更长的序列:”);
而(!prev_round.isEmpty())
{
下一轮。清除();
上一轮forEach(l->len_2_seq.forEach(l2->{
列表合并=合并(l,l2);
if(merge!=null&&!下一轮包含(merge))
{
下一轮。添加(合并);
printSeq(in,merge);
}
}));
count+=下一轮.size();
上一轮清除();
上一轮。添加所有(下一轮);
}
System.out.println();
System.out.println(“找到的总序列:“+count+”输入:“+in”);
}
注:
这是我用来打印序列的方法
private static void printSeq(String in , List<Integer> seq)
{
String seqStr = "";
//convert the sequence of indices into the string represented
//by seq
for(int i : seq)
seqStr += in.charAt(i);
System.out.println(seq + " => " + seqStr);
}
private static void printSeq(字符串输入,列表顺序)
{
字符串seqStr=“”;
//将索引序列转换为表示的字符串
//按顺序
对于(int i:seq)
seqStr+=英寸字符(i);
系统输出打印项次(seq+“=>”+seqStr);
}
大多数代码可以通过多种方式进行优化,但我尽量使其简单。它说:S最多有200个小写字符('a'-'z'),如果你想找到一个200个字符的字符串的所有组合,首先你必须是不朽的。但是,接下来的挑战将完成,需要一些时间,但现在是:最终的解决方案(我已经用你给出的所有示例和一些其他示例对其进行了测试)
private static void printSeq(String in , List<Integer> seq)
{
String seqStr = "";
//convert the sequence of indices into the string represented
//by seq
for(int i : seq)
seqStr += in.charAt(i);
System.out.println(seq + " => " + seqStr);
}