PTA 小明打字 (10分)(数据结构 + 双向链表)

小明打字 (10分)

小明正使用Microsoft Word打一篇文档,文档只包含a-z的小写字母和空格,在打字过程中可能会一次或多次按下Home键、End键、←方向键、→方向键、Insert键、Backspace键。请编写程序,给定小明在键盘上按键的序列,输出小明屏幕上最终显示的文本。 提示:Home键会将当前光标移至文本开始位置,End键当前光标移至文本尾,←键和→键会使当前光标左移或右移一个位置(如果光标在文档头则无法左移,光标在文档尾则无法右移),Insert键会在插入和替换文本间切换(默认是插入状态),Backspace键会删除当前光标前的一个字符。

输入格式:

输入为不超过50000个字符,表示小明的按键序列。包含a-z的小写字母、空格以及字符[、]、{、}、-、=。其中字符“[”表示Home键,“]”表示End键,“{”表示←键,“}”表示→键,“-”表示Insert键,“=”表示Backspace键。

输出格式:

输出为在小明屏幕上最终显示的文本。最后一个字母后没有回车或换行。

样例

输入样例1:

jilin[i lofe{{-v-} ] universiti=y

输出样例1:

i love jilin university

输入样例2:

abcd[c-de

输出样例2:

cdecd

输入样例3:

[[]][][]happy=birthday

输出样例3:

happbirthday

输入样例4:

efg[bbb}}=}}}}=[{{{{a

输出样例4:

abbbe

限制

作者:朱允刚
单位:吉林大学
代码长度限制 : 16 KB
时间限制:25 ms
内存限制:10 MB

解题

题目时间限制为25毫秒,考察数据结构双向链表,解题过程注意维护好双向链表的删除与插入(特别注意首尾位置的删除与插入)
本题采用带空头节点的链表,方便在链表头的插入删除操作

代码

#include <algorithm>  //7-1 小明打字 (10分)
#include <cstring>
#include <iostream>
using namespace std;

typedef struct LNode {
    char ch;
    LNode* next;
    LNode* prev;
} * List;

int main() {
    char ch;
    List start, end, tmp;  //带空头节点链表, 每次插入tmp后面
    List L = new LNode();
    start = L;
    end = L;
    tmp = L;

    bool isInsert = true;

    List ins;
    while (scanf("%c", &ch) && ch != '\n') {
        if (ch == '[') {
            tmp = start;
        } else if (ch == ']') {
            tmp = end;
        } else if (ch == '{') {
            if (tmp->prev) tmp = tmp->prev;
        } else if (ch == '}') {
            if (tmp->next) tmp = tmp->next;
        } else if (ch == '-') {
            isInsert = !isInsert;
        } else if (ch == '=') {  //删除tmp
            if (tmp->prev) {
                List t = tmp;
                tmp->prev->next = tmp->next;
                if (tmp->next) {
                    tmp->next->prev = tmp->prev;
                    tmp = tmp->prev;
                } else {
                    tmp = tmp->prev;
                    tmp->next = NULL;
                }
                delete t;
                if (tmp->next == NULL) end = tmp;  //如果是删除最后的, 更新end
            }
        } else {  // tmp后面添加
            ins = new LNode();
            ins->ch = ch;
            ins->next = tmp->next;
            ins->prev = tmp;
            tmp->next = ins;
            tmp = ins;
            if (tmp->next == NULL) end = tmp;  //如果插入在最后, 更新end
            if (!isInsert && tmp->next) {  //如果是替换, 且tmp下一个存在, 再删除tmp下一个
                List t = tmp->next;
                if (t->next) {
                    tmp->next = t->next;
                    t->next->prev = tmp;
                    delete t;
                } else {	//删除元素在末尾
                    delete t;
                    end = tmp;  //更新end
                    tmp->next = NULL;
                }
            }
        }
        // end->next = NULL;	//保险, 但没必要
    }

    tmp = start->next;
    while (tmp) {
        printf("%c", tmp->ch);
        tmp = tmp->next;
    }
    // 注意清理内存, 这里节省运行时间不清理

    return 0;
}

以下是一个可以解决这个问题的代码示例: ```cpp #include <bits/stdc++.h> using namespace std; int main() { freopen("typist2.in", "r", stdin); freopen("typist2.out", "w", stdout); int n, L; cin >> n >> L; string input; cin >> input; vector<string> wordList(n); for (int i = 0; i < n; ++i) { cin >> wordList[i]; } vector<vector<int>> dp(n + 1, vector<int>(L + 1, 0)); for (int i = 1; i <= n; ++i) { dp[i][0] = i; } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= L; ++j) { if (wordList[i - 1][j - 1] == input[j - 1]) { dp[i][j] = dp[i - 1][j - 1]; } else { dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1; } } } cout << dp[n][L]; return 0; } ``` 这段代码使用了动态规划的思想来解决问题。首先,创建一个二维数组dp,其中dp[i][j]表示将输入的前j个字符变为词汇表中的前i个单词所需的最小操作次数。初始化dp的第一行和第一列,表示将空字符串变为词汇表中的前i个单词或者将输入的前j个字符变为空字符串所需的操作次数。 然后,使用两层循环遍历词汇表和输入的字符,对于每个位置(i, j),如果词汇表中的第i个单词的第j个字符与输入的第j个字符相等,则dp[i][j]等于dp[i-1][j-1],表示不需要操作。如果不相等,则dp[i][j]等于dp[i-1][j]和dp[i][j-1]中较小的值加1,表示选择删除或插入当前字符产生最小操作次数。 最后,输出dp[n][L]即为最终结果,即将输入的所有字符变为词汇表中的所有单词所需的最小操作次数。 注意:该代码是根据题目描述进行编写的,可能与你之前提供的代码有所差异。请测试该代码,如果有任何问题请及时反馈。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值