1.字符串匹配(BF算法)
【问题描述】给定两个字符串S和T,在主串中寻找字串T的过程称为模式匹配,T称为模式。如果匹配成功,返回T在S中的位置;如果匹配失败,返回0。
【输入形式】两行,第一行是主串S,第二行是模式串T
【输出形式】模式串T第一次出现在主串S中的位置。
【样例输入】abcabcacb
abcac
【样例输出】4
【样例说明】注意返回的是模式串在主串的位置,区别存储时的角标。
【评分标准】注意读入字符时,有可能中间含有空格字符。所以可以用getline读取字符串。
#include <iostream>
#include <string>
using namespace std;
int bs(string s, string t);
int main()
{
string s;
string t;
getline(cin, s);
getline(cin, t);
cout << bs(s, t);
}
int bs(string s, string t) {
int i = 0, j = 0;
while ((s[i] !='\0') && (t[j] !='\0')) {
if (s[i] == t[j]) {
i++;
j++;
}
else {
i = i - j + 1;
j = 0;
/*
a b c d a b d e
a b d
主1、主2与模式1、模式2均匹配,主3与模式3不匹配
所有主串从第二个(b)开始和字串第一个比较
*/
}
}
if (t[j] == '\0') return i - j + 1;
else return 0;
}
2.从pos位置开始求子串
【问题描述】
从串str中的pos位置起,求出与substr串匹配的子串的位置,如果str为空串,或者串中不包含与substr匹配的子串,则返回0做标记。
【输入形式】三行,第一行是主串str,第二行是模式串substr;第三行是pos的数值;
【输出形式】模式串substr第一次出现在主串str中从pos位置开始出现的位置(失败时返回0)。
【样例输入】ababcacb
ab
2
【样例输出】
3
#include <iostream>
#include <string>
using namespace std;
int bs(string s, string t,int n);
int main()
{
string s;
string t;
int n;
getline(cin, s);
getline(cin, t);
cout << bs(s, t, n);
}
int bs(string s, string t,int n) {
int i = 0, j = 0;
while ((s[i] != '\0') && (t[j] != '\0')) {
if (s[i] == t[j]) {
i++;
j++;
}
else {
i = i-j+1;
j = 0;
}
}
if (t[j] == '\0') return i-j + 1;
else return 0;
}
3.字串出现次数的统计
【问题描述】编写一个函数,计算一个子串在一个主串中出现的次数,如果该字串不出现,则返回0。本题不需要考虑子串重叠,如:主串为aaaa,子串为aaa,考虑子串重叠结果为2,不考虑子串重叠结果为1。
【输入形式】主串S和子串T。
【输出形式】子串在主串中出现的次数,如果没有出现,则输出0。
【样例输入】
ABCDFDEG
CD
【样例输出】1
【样例说明】子串CD在主串中出现了一次
#include <iostream>
#include <string>
using namespace std;
int bs(string s, string t) {
int i = 0, j = 0;
int count = 0;
while (s[i] != '\0') {//条件改为主串不为零,(一直往下匹配直至主串到头)
if (s[i] == t[j]) {
i++;
j++;
}
else {
i = i - j + 1;
j = 0;
}
if (t[j] == '\0') {
count++;
//i++;无需此条,模式到头后,主串并没有到头,会继续执行循环
//若加上i+,会出现跳跃
j = 0;
}
}
if (s[i] == '\0') return count;
else return 0;
}
int main()
{
string s;
string t;
int n;
getline(cin, s);
getline(cin, t);
cout << bs(s, t);
}
4.公共子序列
【问题描述】模式匹配时严格的匹配,即强调模式在主串中的连续性,例如,模式“bc”是主串"abcd"的子串,而"ac"就不是主串“abcd”的子串。但在实际应用中,有时不需要模式的连续性,例如,模式“曲师大”与主串“曲阜师范大学”是非连续匹配,称模式“曲师大”是主串“曲阜师范大学”的子序列。要求设计算法,判断给定的模式是否为两个主串的公共子序列。如果是公共子序列,则输出“YES”;否则输出“NO”。
【输入形式】第一行是主串S1、第二行是主串S2、第三行是子串T。
【输出形式】子串T是否是主串S1和S2的公共子序列。如果是则输出“YES”,否则输出“NO”。
【样例输入】
abcdef
cdef
cd
【样例输出】YES
#include <iostream>
#include <string>
using namespace std;
int mat(string s, string t);
int main()
{
string s;
string t;
string m;
getline(cin, s);
getline(cin, t);
getline(cin, m);
int a = mat(s, m);//比较3是否是1的子序列
int b = mat(t, m);//比较3是否是2的子序列
if (a && b) cout << "YES";
else cout << "NO";
}
int mat(string s, string t) {//判断是否是子串的函数
int i = 0, j = 0;
while ((s[i] != '\0') && (t[j] != '\0')) {
if (s[i] == t[j]) {
i++;
j++;
}
else {
i++;//i继续往前走,只需要主串中含有模式中的字符就可以,无需每次回溯
/*
a b c d a b d
a b d
第三个不符合,模式第三个继续和主串第4个比,依次往下,直至找到
*/
}
}
if (t[j] == '\0') return 1;//返回值为1
else return 0;
}
5.移动非零元素
【问题描述】设数组A[0,……,n-1]的n个元素中有多个零元素,设计一个算法,将A中所有的非零元素依次移动到A数组的前端。最后打印数组A,保证非零元素都在前端输出。
【输入形式】数组元素的个数n以及数据元素(中间用空格隔开)。
【输出形式】移动非零元素后的数组。
【样例输入】
8
1 0 0 3 0 1 0 2
【样例输出】1 3 1 2 0 0 0 0
【提示说明】从左到右扫描整个数组,当发现非零元素时,使其尽可能与靠左边的零元素进行交换。
#include <iostream>
using namespace std;
int change(int *a,int *b) {
int t;
t = *a;
*a = *b;
*b = t;
return *a;
}
int main() {
int n;
cin >> n;
int arr[100];
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
for (int i = 0; i < n; i++) {//比较n次,类似冒泡
for (int j = 0; j < n - 1; j++) {//左边与右边交换位置
if (arr[j] == 0) {
change(&arr[i], &arr[j]);
}
}
}
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
}
6.字符串匹配(KMP算法)
【问题描述】给定两个字符串S和T,在主串中寻找字串T的过程称为模式匹配,T称为模式。如果匹配成功,返回T在S中的位置;如果匹配失败,返回0。记主串S的长度为n,模式串T的长度为m,则传统BF算法最好情况下的时间复杂度为O(n+m),最差情况下的时间复杂度为O(n*m),时间复杂度太高,而且主要是由于主串回溯造成的,为了减少主串无意义的回溯,所以提出了KMP算法,在KMP算法中需要用到next数组,因而先根据模式串求解出next数组。
【输入形式】两行,第一行是主串S,第二行是模式串T
【输出形式】第一行表示模式串T第一次出现在主串S中的位置(失败时返回0)。第二行是KMP算法中next数组的内容(中间用空格隔开)。
【样例输入】
abcabcacb
abcac
【样例输出】
4
-1 0 0 0 1
【样例说明】1、注意返回的是模式串在主串的位置,区别存储时的角标。
#include <iostream>
#include <string>
using namespace std;
int KMP(string S, string T,int next[]) {
int i = 0;
int j = 0;
while ((S[i] != '\0') && (T[j] != '\0')) {
if (S[i] == T[j]) {
i++;
j++;
}
else {
j = next[j];
}
if (j == -1) {
i++;
j++;
}
}
if (T[j] == '\0') {
return i - j + 1;
}
else return 0;
}
int acount(string t) {
int n = 0;
while (t[n]!='\0') {
n++;
}
return n;
}
void getNext(string T, int length, int next[])//计算next函数值
{
int m = 0, k = -1;
next[0] = -1;
while (m < length)
{
if (k == -1 || T[m] == T[k])
next[++m] = ++k;
else
k = next[k];
}
}
int main()
{
string s;
string t;
getline(cin, s);
getline(cin, t);
int n = acount(t);
int next[100];
getNext(t, n, next);
cout << KMP(s, t, next) << endl;
for (int g = 0; g < n; g++) {
cout << next[g]<<" ";
}
}
7.稀疏矩阵的打印输出
【问题描述】
若一个稀疏矩阵A中的非零元素
以三元组的形式按照行优先的次序存储在三元组顺序表中,则打印输出对应的稀疏矩阵。
【输入形式】
输入的第一行三个数据分别为矩阵的行数mu、列数nu、非零元素值的个数tu,以空格间隔;
接下来共tu行,每行各三个数据,分别是非零元素的行标、列标、数值,以空格间隔。
【输出形式】三元组对应的稀疏矩阵。(每行中的元素中间以5个空格隔开)
【样例输入】
5 4 5
1 1 3
1 4 7
2 3 -1
3 1 2
5 4 -8
【样例输出】
3 0 0 7
0 0 -1 0
2 0 0 0
0 0 0 0
0 0 0 -8
#include <iostream>
using namespace std;
const int MaxSize = 100;
/*三元组结构体*/
template <class DataType>
struct element {
int row, col; //非零元素的行、列
DataType item; //非零元素值
};
template <class DataType>
class SparseMatrix {
public:
SparseMatrix();
void printMatrix();
void printSparseMatrix();
void trans2(SparseMatrix<DataType>& B);
private:
element<DataType> data[MaxSize]; //存储三元组表
int mu, nu, tu; //分别表示稀疏矩阵的行数、列数、非零元素的个数
};
/*三元组顺序表的构造*/
template <class DataType>
SparseMatrix<DataType>::SparseMatrix()
{
int row, col, num;
cin >> row >> col >> num; //稀疏矩阵的行数、列数
mu = row;
nu = col;
tu = num; //存储时从0开始
for (int k = 0; k < num; ++k) {
int i, j, temp;
cin >> i >> j >> temp;
data[k].row = i;
data[k].col = j;
data[k].item = temp;
}
}
/*稀疏矩阵的打印*/
template <class DataType>
void SparseMatrix<DataType>::printMatrix()
{
int a[100][100];
int i, j;
for (i = 0; i < mu; i++) {
for (j = 0; j < nu; j++) {
a[i][j] = 0;
}
}
for (int k = 0; k <tu; k++) {
a[data[k].row-1][data[k].col-1] = data[k].item;
}
for (i = 0; i < mu; i++) {
for (j = 0; j < nu; j++) {
cout<<a[i][j]<<" ";
}
cout << endl;
}
}
int main()
{
SparseMatrix<int> A;
A.printMatrix();
return 0;
}
8.矩阵的鞍点
【问题描述】 若在一个矩阵A中存在一个元素
该元素是第i行的最小值元素且又是第j列的最大值元素,则称此元素是该矩阵的一个鞍点。假设以二维数组存储矩阵,设计算法求矩阵A的所有鞍点(输出鞍点的数值、行号、列号),若矩阵中不存在鞍点,应给出相应的信息(No answer)。
【输入形式】
输入的第一行两个数据分别为矩阵的m,n值,以空格间隔;
第二行为整型数组中的所有元素,以空格间隔,按行来保存数据。
【输出形式】输出所有的马鞍点,包括鞍点值,以及所在行和列;若无,打印 no。
【样例输入】
5 5
1 2 3 4 5 7 3 4 5 6 2 1 5 4 3 5 3 6 5 4 5 3 6 5 4
【样例输出】
3 2 2
3 4 2
3 5 2
【样例说明】输入5*5的矩阵,第一行的数据为1 2 3 4 5,第二行 7 3 4 5 6,以此类推:
1 2 3 4 5
7 3 4 5 6
2 1 5 4 3
5 3 6 5 4
5 3 6 5 4
输出本数组中的三个马鞍点3(2行2列) 3(4行2列) 3(5行2列)。
#include <iostream>
using namespace std;
void saddlePoint(int** A, int n, int m)
{
int i, j;
int max[10] = { 0 }, min[10] = { 0 };//存放每行最小值,每列最大值
int MIN, MAX;
for (i = 1; i <=n; i++) {//每行遍历
MIN = A[i][1];//每行第一个
for (j = 1; j <=m; j++) {//每列遍历
if (MIN > A[i][j]) {
MIN = A[i][j];
}
}
min[i] = MIN;//求每行最小值,并存入数组
}
for (j = 1; j <=m; j++) {//每行遍历
MAX = A[1][j];//每列第一个
for (i = 1; i <=n; i++) {//遍历每一行
if (MAX < A[i][j]) {
MAX = A[i][j];
}
}
max[j] = MAX;//求每列最大值,并存入数组
}
int flag = 0;
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
if (A[i][j] == min[i] && A[i][j] == max[j]) {//遍历寻找同时满足的值
flag = 1;
cout << A[i][j] << " " << i << " " << j << endl;
}
}
}
if (flag == 0) cout << "No answer";
}
int main()
{
int n, m;
cin >> n >> m;
int** arr = new int* [n + 1];
for (int i = 0; i <= n + 1; ++i)
arr[i] = new int[m + 1];
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> arr[i][j];
saddlePoint(arr, n, m);
return 0;
}