USACO Calf Flac题解

本文介绍了一种使用O(n)动态规划算法解决寻找字符串中最长回文子序列的问题,通过分析并给出具体实现代码,展示了如何有效减少时间和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这一题有点烦

我一开始的思路是,回文序列么,就是正序字符串和逆序字符串中相同的那一串

于是乎,就转化成求最长公共子字符串,于是用动态规划,O(N^2)的时间复杂度和空间复杂度

首先是内存超了,于是换成O(n)空间复杂度的实现方式,即只记录上一状态就可以

接着到最后一个测试程序的时候,时间也超了

 

无奈,想不出其他思路的情况下,看了NOCOW的解题,O(n)的动态规划

思路是这样的:

写道
begin
if cha[i]=cha[i-1] then f[i]:=i-1;
if cha[i]=cha[f[i-1]-1] then f[i]:=f[i-1]-1;
end;

 

以下是代码,注释部分是我一开始的思路:

/*
ID: bbsunch2
PROG: calfflac
LANG: C++
*/
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <algorithm>

using namespace std;

int main()
{
    ofstream fout ("calfflac.out");
    ifstream fin ("calfflac.in");
    string input = "";
    while(fin.good() && !fin.eof())
    {
        string line;
        getline(fin,line,'\n');
        input = input + line + "\n";
    }
    //cout << input << endl;
    //建立字符串中的字母和原始字符串位置对应关系
    int charIndicator = -1;
    vector<int> correspondingPosition;
    string letterString = "";
    for(int i = 0; i < input.size(); i++)
    {
        char single = input[i];
        if(single >= 'A' && single <= 'Z')
        {
            charIndicator++;
            letterString += single;
            correspondingPosition.push_back(charIndicator);
        }else if(single >= 'a' && single <='z')
        {
            single = single - 32;
            charIndicator++;
            letterString += single;
            correspondingPosition.push_back(charIndicator);
        }else
        {
            charIndicator++;
        }
    }
    vector<int> f;
    f.push_back(0);
    for(int i = 1; i < letterString.size(); i++)
    {
        if(letterString[i] == letterString[f[i-1]])
        {
            f.push_back(i-1);
            if(letterString[i] == letterString[f[i-1]-1])
            {
                f[i] = (f[i-1]-1);
            }
        }else if(f[i-1] - 1 >=0)
        {
            if(letterString[i] == letterString[f[i-1]-1])
            {
                f.push_back(f[i-1]-1);
            }else
            {
                f.push_back(i);
            }
        }else
        {
            f.push_back(i);
        }
    }
    int maxI = 0;
    int maxStep = 0;
    for(int i = 1; i < letterString.size(); i++)
    {
        if(maxStep < i-f[i]+1)
        {
            maxStep = i - f[i]+1;
            maxI = i;
        }
    }
    /*string reverseLetterString = "";
    for(int i = letterString.size()-1; i >= 0; i--)
    {
        reverseLetterString += letterString[i];
    }
    //vector<vector<int> > matrix;
    int maxI = 0;
    int maxStep = 0;
    vector<int> line1;
    vector<int> line2;
    for(int i = 0; i < letterString.size(); i++)
    {
        line1.push_back(0);
        line2.push_back(0);
    }



    for(int i = 0; i < letterString.size(); i++)
    {
        vector<int> lineInMatrix;
        for(int k = 0; k < letterString.size(); k++)
        {
            lineInMatrix.push_back(0);
        }
        matrix.push_back(lineInMatrix);
    }


    for(int k = 0; k < reverseLetterString.size(); k++)
    {
        for(int i = 0; i < letterString.size(); i++)
        {
            line2[i] = 0;
            if(letterString[i] == reverseLetterString[k])
            {
                if(i == 0 || k == 0)
                {
                    line2[i] = 1;
                }else
                {
                    line2[i] = line1[i-1] + 1;
                }
                if(maxStep <= line2[i])
                {
                    maxStep = line2[i];
                    maxI = i;
                }
            }
        }
        for(int index = 0; index < letterString.size(); index++)
        {
            line1[index] = line2[index];
        }

    }*/
    fout << maxStep << endl;
    int startLetterPosition = maxI - maxStep + 1;
    int startPosition = correspondingPosition[startLetterPosition];
    int endPosition = correspondingPosition[maxI];

    string sub = input.substr(startPosition, endPosition - startPosition + 1);

    fout << sub << endl;

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值