HW2016_字符串_STL_DP

一、在字符串str1中删除那些在str2中出现的字符。

str2可能会有重复字符,直接遍历会导致效率低下,故先借助STL的set容器对str1查重;

然后,遍历str1和str2,对str1进行查重。

#include <iostream>
#include <string>
#include <set>

using namespace std;

void deleteChar(char* strRet, const string& str1,int len1, const string& str2,int len2)
{
    if(len1 < 1)                   //异常检测
    {
        return;
    }
    bool findIt = false;      //查找标记位

    set<char>mySet;
    int i = 0,j = 0,k = 0;
    for(i = 0; i < len2; ++i)  //str2去重复字符
    {
         mySet.insert(str2[i]);
    }

   for(j = 0; j < len1; j++)
    {
       for(set<char>::iterator it = mySet.begin(); it != mySet.end(); ++it)
       {
           if(str1[j] == *it && findIt == false)
           {
               findIt = true;
               break;
           }
       }//end for

       if(!findIt)
       {
           strRet[k++] = str1[j];
       }
       findIt = false;    //标记位置位

    }//end for
   strRet[k] = ''; //c风格字符串结束标志

}

int main()
{
    string str1,str2;
    while(cin >> str1 >> str2)
    {
        int len1 = str1.size();
        int len2 = str2.size();
char* strRet = new char[len1 + 1]; //申请空间存放查重后的字符串 deleteChar(strRet,str1,len1,str2,len2); cout << strRet << endl; delete strRet; //防止内存泄漏 return 0; } }

二、

编程题-成绩排名

题目总共包含如下两种格式的字符串命令:

1 LOD GRADE命令,其格式为:

LOD GRADE:NAME=XiaoMing,MATH=80,LANG=90;

(1)此命令用于导入学生成绩

(2)NAME字段表示学生姓名

(3)MATH字段表示学生数学成绩

(4)LANG字段表示学生语文成绩

(5)MATH字段和LANG字段顺序不一定是MATH在前,LANG在后

(6)相同的分数,名词相同,后面的名次孔雀:例如100,99,99,99,98,98,名次1,2,2,2,5,5

(7)此命令会连续执行,直到遇到第一个LST GRADE

2 LST GRADE命令,其格式为:

LST GRADE:NAME=XiaoHong;

(1)此命令用于查询学生成绩

(2)NAME字段表示学生姓名

(3)查询结果格式:姓名 数学 语文 总分 数学排名 语文排名 总排名

(4)每组用例,此命令仅执行一次

样例输入

LOD GRADE:NAME=XiaoMing,MATH=80,LANG=90;

LOD GRADE:NAME=XiaoHong,LANG=60,MATH=100;

LOD GRADE:NAME=XiaoMei,MATH=70,LANG=90;

LST GRADE:NAME=XiaoHong;

样例输出 XiaoHong 100 60 160 1 3 2

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstdlib>

using namespace std; 
const string LOD = "LOD GRADE";
const string LST = "LST GRADE";
int myCout = 0;

class student{
public:
    student(string str)
    {
        OPE = "";
        unsigned int posOPE = str.find_first_of(':');
        if( posOPE < str.size())
            OPE = str.substr(0, posOPE);
        unsigned int posNAME1 = str.find_first_of('=');
        unsigned int posNAME2 = str.find_first_of(',');
        NAME = str.substr(posNAME1 + 1, posNAME2 - posNAME1 - 1);

        unsigned int posEnd = str.find_last_of(';');
        unsigned int posMATH = str.find_last_of('H');
        unsigned int posLANG = str.find_last_of('G');
        unsigned int posLastCommer = str.find_last_of(',');

        if(posEnd - posMATH > 5)
        {
            MATH = atoi(str.substr(posMATH + 2, posLastCommer - posMATH - 2).c_str());
            LANG = atoi(str.substr(posLastCommer + 6, posEnd - posLastCommer -6).c_str());
        }
        else
        {
            MATH = atoi(str.substr(posMATH + 2, posEnd - posMATH - 2).c_str());
            LANG = atoi(str.substr(posLANG + 2, posLastCommer - posLANG - 2).c_str());
        }

        totalScore = MATH + LANG;
        mathMarking = 0;
        langMarking = 0;
        totalMarking = 0;
        count = 0;
    }
    ~student(){}
    string OPE;
    string NAME;
    int MATH;
    int LANG;
    int totalScore;
    int mathMarking;
    int langMarking;
    int totalMarking;
    int count;
};
bool mathCompare(student*& stu1, student*& stu2)
{
    return (stu1->MATH > stu2->MATH) ||
           (stu1->MATH == stu2->MATH && stu1->count < stu2->count);         //desc  ; 成绩相等,按照出现的顺序排序
}
bool langCompare(student*& stu1, student*& stu2)
{
    return (stu1->LANG > stu2->LANG) ||
           (stu1->LANG == stu2->LANG && stu1->count < stu2->count);         //desc  
}

bool totalCompare(student*& stu1, student*& stu2)
{
    return (stu1->totalScore > stu2->totalScore) ||
           (stu1->totalScore == stu2->totalScore && stu1->count < stu2->count);         //desc  
}

int main()
{
    string str;
    vector<student* >students;
    while(getline(cin, str))   //去读一行,使用cin>>会有缓冲区的问题(空格,tab,回车)
    {
        //fill into vector
        student* stu = new student(str);

        if(LOD == stu->OPE)
        {
            students.push_back(stu);
            stu->count = myCout++;  //用于记录学生出现的顺序
        }
        if(LST == stu->OPE)
        {
           string stuName = "";     //提取学生姓名,用于匹配查找
           unsigned int posNAME01 = str.find_last_of('=');
           unsigned int posNAME02 = str.find_last_of(';');
           stuName = str.substr(posNAME01 + 1, posNAME02 - posNAME01 - 1);

            sort(students.begin(),students.end(),mathCompare);
            for(int i = 0; i < students.size();++i)
            {
                if(students[i]->NAME == stuName)
                    students[i]->mathMarking = i+1;    //根据数学成绩排序规则,给学生的数学排名赋值
            }
            sort(students.begin(),students.end(),langCompare);
            for(int i = 0; i < students.size();++i)
            {
                if(students[i]->NAME == stuName)
                    students[i]->langMarking = i+1;
            }
            sort(students.begin(),students.end(),totalCompare);
            for(int i = 0; i < students.size();++i)
            {
                if(students[i]->NAME == stuName)
                    students[i]->totalMarking = i+1;
            }
            for(int i = 0; i < students.size();++i)
            {
                if(students[i]->NAME == stuName)    //输出查找学生的信息
                cout << students[i]->NAME << " " << students[i]->MATH << " "
                     << students[i]->LANG << " " << students[i]->totalScore << " "
                     << students[i]->mathMarking << " " << students[i]->langMarking
                     << " " <<students[i]->totalMarking;
            }

        }

    }//while

    return 0;
}

三、

给出两个字符串A,B。将A字符串转化为B字符串,转化共两种方式:删除连续的n个字符,一次操作费用为2。增加连续的n个字符(增加的什么由你决定),一次操作的费用为n+2。求把A变为B最小费用。

输入:第一行输入一个正整数(1<=T<=10),表示有T组测试数据。
对于每组测试数据:
两行字符串A,B(字符串长度不超过2000,字符仅包含小写字母。)

输出:对于每组测试数据,输出一行一个整数,表示最小费用。
样例输入
2
dsafsadfadf
fdfd
aaaaaaaa
bbbbbbbb

样例输出:
7
12

 分析:参考知乎(时间复杂度O(N3)),后面自己有时间复杂度O(N2)的方法。

结尾应该只有三种情况即(不修改,删除结尾,添加结尾).
1. 不修改, 只有当str1[j - 1] == str2[i - 1]的情况才可能存在, 此时费用等于将A[0:i-1]变换为B[0:j-1]的最小费用(三种方式中最小的那个),否则为INF
2. 添加结尾, 考虑添加的长度为k,此时费用为将A[0:i]变换成B[0:j-k]再加上一个根据结尾不同变换的COST1
3. 删除结尾, 考虑删除的长度为k,此时费用为将A[0:i-k]变换为B[0:j]再加上一个根据结尾不同变换的COST2
(Delete: Min(F(0, m),...,F(n-1, m))+2;)
( Insert: Min(F(n,0)+m,...,F(n, m-1)+1)+2;)
作者:AbmiP
链接:https://www.zhihu.com/question/50960106/answer/123577803
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define INF 3000
using namespace std;
int de[2010][2010], ae[2010][2010], ne[2010][2010];
char s1[2010], s2[2010];
int main() {
    //freopen("io/in.txt", "r", stdin);freopen("io/out.txt", "w", stdout);
    int n, l1, l2;
    char c;
    scanf("%d%c", &n, &c);
    while (n--) {
        char* tmp = s1;
        char c;
        while ((scanf("%c", &c) != EOF) && c != '
')*(tmp++) = c;
        *tmp = '';
        tmp = s2;
        while ((scanf("%c", &c) != EOF) && c != '
')*(tmp++) = c;
        *tmp = '';
        l1 = strlen(s1);
        l2 = strlen(s2);
        for (int i = 0; i <= l1; i++) {
            de[0][i] = 2; ae[0][i] = ne[0][i] = INF;
        }
        for (int i = 0; i <= l2; i++) {
            ae[i][0] = i + 2; de[i][0] = ne[i][0] = INF;
        }
        ne[0][0] = 0;
        for (int j = 1; j <= l2; j++)
            for (int i = 1; i <= l1; i++) {
                ne[j][i] = s1[i - 1] == s2[j - 1] ? min(min(ne[j-1][i-1], ae[j-1][i-1]), de[j-1][i-1]) : INF;
                ae[j][i] = de[j][i] = INF;
                for (int k = 1; k <= j; k++)
                    ae[j][i] = min(ae[j][i], min(ae[j - k][i] + k, min(de[j - k][i] + k + 2, ne[j - k][i] + k + 2)));
                for (int k = 1; k <= i; k++)
                    de[j][i] = min(de[j][i], min(de[j][i - k], min(ae[j][i - k] + 2, ne[j][i - k] + 2)));
            }
        printf("%d
", min(min(ne[l2][l1], ae[l2][l1]), de[l2][l1]));
    }
    return 0;
}

O(N2):

addEnd[i][j]表示通过增加字符,使得str1[0 : j]变换为str2[0 : i];

delEnd[i][j]表示通过删除字符,使得str1[0 : j]变换为str2[0 : i];

noEnd[i][j]表示不做变换,使得str1[0 : j]变换为str2[0 : i]。

#include <iostream>
#include <cstring>

using namespace std;

#define max 2001
#define INF 10000

int addEnd[max][max];
int delEnd[max][max];
int noEnd[max][max];

int MIN(int x,int y)
{
    if(x>y)
        return y;
    else
        return x;
}
void initArray(int addEnd[][max], int delEnd[][max], int noEnd[][max], int len1, int len2)
{
    for(int i = 0; i <= len1; i++)
    {
        delEnd[0][i] = 2;
        addEnd[0][i] = noEnd[0][i] = INF;
    }
    for(int i = 0;i <= len2; i++)
    {
        addEnd[i][0] = i + 2;
        delEnd[i][0] = noEnd[i][0] = INF;
    }
    noEnd[0][0] = 0;
}
void refreshArray(int addEnd[][max],int delEnd[][max],int noEnd[][max],const char* str1,int len1,const char* str2,int len2)
{
    for(int i = 1;i <= len2; i++)
    {
        for(int j = 1;j <= len1; j++)
        {
            noEnd[i][j]  = (str1[j-1]==str2[i-1]) ? MIN(addEnd[i-1][j-1],MIN(delEnd[i-1][j-1],noEnd[i-1][j-1])) : INF;

            delEnd[i][j] = addEnd[i][j] = INF;

            addEnd[i][j] = MIN(addEnd[i][j], MIN(addEnd[i-1][j]+1, MIN(delEnd[i-1][j]+1+2, noEnd[i-1][j]+1+2)));

            delEnd[i][j] = MIN(delEnd[i][j],MIN(addEnd[i][j-1]+2,MIN(delEnd[i][j-1],noEnd[i][j-1]+2)));

        }
    }
}

int main()
{
    int num;
    while(cin >> num)
    {
        int ret[num];
        int retID = 0;
        int retSize = num;
        while(num > 0)
        {
            char str1[max];
            char str2[max];

            cin >> str1 >> str2;
            int len1 = strlen(str1);
            int len2 = strlen(str2);

            //数组边界预定义
            initArray(addEnd, delEnd, noEnd, len1, len2);
            //刷新数组
            refreshArray(addEnd, delEnd, noEnd, str1, len1, str2, len2);
            //保存结果
            ret[retID++] = MIN(addEnd[len2][len1],MIN(delEnd[len2][len1],noEnd[len2][len1]));  
//此处,切不可使用++retID(先自增为1,并将自增后的值赋给下标);而retID++是自增,并将自增前的值赋给小标。  回忆一下STL中map删除中 it++的用法
            --num;
        }//end while
        
        //result display
        for(int i = 0; i < retSize; i++)
        {
            cout << ret[i] << endl;
        }
    }//end while
    return 0;
}
原文地址:https://www.cnblogs.com/Lunais/p/5929406.html