データ構造 ---- 構造 - 線形構造 - 文字列
1. 文字列の定義方法
最初:
char* str1="Hello"
2 番目のタイプ:
char str2[]="Hello";
違い
1.地域が違う
//str1在常量区
//str2在这里的写法是在栈区
2. 要素の変更の可否
//str1中的元素不可改
//str2中的元素可改
//第一种
//用下标进行修改
//第二种
//用strcpy函数进行修改
3. str1、str2の変更可否
//str1可改,它是指针可以改变指向
str1="Haha";
//str2不可改,它是地址不可改
4. さまざまなサイズ
sizeof(str1);//4个字节
sizeof(str2);//6个字节
2. 文字列置換に関する質問
トピック:
十分に長い文字列のスペースを win に置き換えます。元の文字列は「恋人たちだけが生き残った」です (この文字列は無限に長く、「e」文字の後には無限のスペースがあります)。
方法:
1. strlen (文字列) + 使用する追加スペースのサイズの新しいスペースを激しく申請します
元の文字列をトラバースし、スペースに遭遇したときにそれを新しいスペースに保存するか、元の文字を新しいスペースに保存します
時間計算量 O(n) 空間計算量 O(n)
2. 弦のカットと接続
カット機能はstrtokです
接続されている関数は strcat です
時間計算量 O(n) 空間計算量 O(n)
3. スタック時間の計算量 O(n) 空間の計算量 O(n)
4. キュー時間の複雑さ O(n) 空間の複雑さ O(n)
5. 暴力(最適化)
1. 元の空間上に 2 つのポインターを定義します
2. 1 つは最後の文字の位置を指し、もう 1 つはスペースを置換した後の位置を指します (この位置は strlen (文字列) + 使用される追加のスペースです)
3. 2 つのポインタが同時に前方に移動し、スペースが見つかった場合は、後者のポインタが指す位置でそれを win に置き換えます (最初に n を置き換えてからポインタが前方に移動し、置き換えが完了するまで同様に続きます) )、スペースでない場合は、前のポインタを指します。位置の内容を次のポインタが指す位置に置き換えます。その後、前のポインタの次のポインタが要素でなくなるまで、2 つのポインタが一緒に前進します。この文字列の中で。
時間計算量 O(n) 空間計算量 O(1)
3. 文字列の単語の反転について
トピック:
「恋人のみ残された」という文字列を「恋人のみ残された」に反転する
方法:
1. アレイ
2 つのポインタを定義し、1 つは文字列の後ろから前までのスペースではない最初の文字を指し、もう 1 つは先頭のこれを指し、前方にトラバースします。スペースが見つかったら、すべての文字を配置します。この段落の文字 新しい配列では、次のポインタが最初のポインタの位置に来て、この位置から再びスペースではない最初の文字を見つけます。その後、別のポインタもここを指し、次に走査します。前方に進み、スペースが見つかったら、この段落内のすべての文字を新しい配列に入れます
2 つのポインタは、前のポインタが文字列の最初の要素を指すまで上記のプロセスを繰り返し、2 つのポインタが同じ要素を指しているかどうかを確認し、そうでない場合は、この段落内のすべての文字を新しい配列に入れます。 「はい」の場合は、反転が完了します。
時間計算量 O(n) 空間計算量 O(n)
2. 反転
まず文字列全体を反転し、次に各単語を反転します
時間計算量 O(n) 空間計算量 O(1)
3. リンクリスト
各単語をリンク リストに保存し、前から後ろにヘッド補間法を使用してリンク リストを新しいリンク リストに変換します
時間計算量 O(n) 空間計算量 O(n)
4.スタック
(1) スタック + 配列
文字列をスタックに置き、スペースが見つかった場合は、スタック内の要素をポップして配列に入れます(配列は事前にスペースを申請しています)
文字列が空の場合は、要素をスタックにポップし、配列に入れます。
時間計算量 O(n) 空間計算量 O(n)
(2) 2 つのスタック
すべての文字列を最初のスタックに入れてから、最初のスタックの要素を 2 番目のスタックにポップします。
スペースが見つかった場合は、2 番目のスタックの要素を元の文字列の対応する位置に置き換えます (ここには文字を置き換えるポインタがあり、文字が置き換えられるたびにポインタは 1 ビット後方に移動します)ポインタは最初に文字列の最初の要素を指します)、その後、最初のスタック内の要素がポップされます
最初のスタックに要素がなくなるまで、2 番目のスタックに要素があれば、2 番目のスタックのすべての要素がポップアウトされ、元の文字列の対応する位置に置き換えられます
時間計算量 O(n) 空間計算量 O(n)
5. 弦のカットと接続
文字列の単語反転問題のアップグレード版 (この問題の URL は https://leetcode.cn/problems/reverse-words-in-a-string/ です)
トピック:
文字列が与えられた場合s
、文字列内の単語の順序を逆にしてください。
単語は、空白文字以外の文字で構成される文字列です。文字列内の単語はs
少なくとも 1 つのスペースで区切ります。
単語を反転し、単語を1 つのスペースで結合した結果の文字列を返します。
**注意:**s
入力文字列内の単語の間には、先頭のスペース、末尾のスペース、または複数のスペースが存在する場合があります。返される結果文字列では、単語は 1 つのスペースでのみ区切られ、余分なスペースは含まれないようにしてください。
上記の分析に適用される反転メソッドのコードは次のとおりです。
//这里的代码是c++语言下的
class Solution {
public:
string reverseWords(string s) {
//删除首尾的空格
s.erase(0, s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ")+1);
//整体进行翻转
int begin1 = 0;
int end1 = s.size() - 1;
while (begin1 < end1) {
char a = s[begin1];
s[begin1] = s[end1];
s[end1] = a;
begin1++;
end1--;
}
//每个单词进行翻转
int begin = 0;
int end = 0;
char* p = &s[0];
int index = 0;
int bool1 = 1;
int bool2 = 1;
int bool3 = 0;
int bool4 = 0;
int bool5 = 0;
while (*p != '\0') {
if (*p != ' ' && *(p + 1) != ' '&&bool1%2==1) {
begin = index;
bool1++;
bool3 = 1;
}
if ((*p == ' ' && *(p - 1) != ' ' && bool1 % 2 == 0)) {
end = index - 1;
bool1++;
bool4 = 1;
}
if (*(p + 1) == '\0' && *p !=' ' && bool1 % 2 == 0) {
end = index;
bool1++;
bool4 = 1;
}
int begin2 = begin;
int end2 = end;
while (begin2 < end2&& bool3&& bool4) {
bool5 = 1;
char a = s[begin2];
s[begin2] = s[end2];
s[end2] = a;
begin2++;
end2--;
}
if (bool5) {
bool3 = 0;
bool4 = 0;
bool5 = 0;
}
p++;
index++;
}
//去除字符串间的空格
string::iterator ite = s.begin();
while (ite!=s.end()) {
if (*ite == ' ' && *(ite + 1) == ' ') {
ite=s.erase(ite);
}
else if (*ite == ' ' && *(ite - 1) == ' ') {
ite = s.erase(ite);
}
else {
ite++;
}
}
return s;
}
};
4. 文字列についての質問
トピック:
文字列「abcdefgh」、k を入力、最初の k 文字を文字列の後ろに移動、移動された k 文字の順序は変更されません。k が 3 の場合、移動された文字列は「defghabc」になります。
方法:
1. キュー/スタック
2. リンクされたリスト/配列
3. 弦のカットと接続
4. 反転
まず文字列全体を反転し、次に0~k-1番目の文字をその間の文字を含めて反転し、k~最後の文字をそれらの間の文字を含めて反転します
時間計算量 O(n) 空間計算量 O(1)
5. 文字列検索に関する質問
1. 経験に基づいて次の 4 つの主要な検索問題を要約します。
1. 文字列の中から特定の条件を満たす文字を検索します。
2. 文字列内の条件を満たす文字列を検索します。
3. 複数の文字列の中から特定の文字列を検索する
4. 2 つの文字列の条件を満たす共通の文字列をいくつか見つけます。
1. 検索質問の最初の質問
トピック:
1 回だけ出現する最初の文字を検索します
解決する:
1. キュー+カウンター
2.マップ+トラバーサル
3.ハッシュ+トラバーサル
2. 2 番目に大きな検索の問題
トピック:
文字列内の最長の回文部分文字列を検索します
解決する:
1. 文字列が回文の部分文字列であるかどうかを判断し、文字列を中間から切断し、文字列を後ろに反転して、2 つの文字列を比較して等しいかどうかを確認します。
2. 次に長さを比較します
3. 2 番目に大きな探索問題における KMP アルゴリズム
1. KMPアルゴリズムの役割
KMP アルゴリズムは、別の文字列 (メイン文字列) 内の文字列 (文字列) の位置 (最初の要素の位置) を見つけるために使用されます。
2. KMPの実施
1. まず、文字列内の各要素のプレフィックス文字列とサフィックス文字列を同じ最大長で格納する Next 配列を定義します。
1. 隣接する 2 つの変数を添字として定義します
2. 後の添字が配置されている要素が、次の配列の添字として機能する前の添字によって見つかった要素と同じである場合、この要素が配置されている次の配列の値は、前の要素の値になります。次の配列要素の値で見つかった添え字 +1
3. それらが同じでなく、次の配列で見つかった前の要素の添字の値が 0 の場合、この要素が添字付けされている次の配列の値は 0 になります。
4. それらが同じでなく、次の配列で見つかった前の要素の添字の値が 0 でない場合、前の変数は添字で見つかった値 -1 になり、次の配列で添字として配置されます。そして、見つかるまで、または見つかった部分文字列の先頭ノードが見つからなくなるまで、操作 2 を繰り返します。
2. サブ文字列とメイン文字列を一致させます。
1. サブ文字列要素がメイン文字列要素と同じである場合は、比較を続行します。
2. サブストリング要素がメインのストリング要素と同じでない場合、サブストリングの先頭要素が等しくありません。一致する文字列は先頭から始まります
3. 部分文字列の走査が終了するか、主文字列の走査が完了するまで、終了します。
3. KMP コードは次のとおりです。
//此代码是使用c写的
#include<stdio.h>
#include<stdlib.h>
int* GetNext(const char* match) {
int* pNext = (int*)malloc(sizeof(int) * strlen(match));
pNext[0] = 0;
int i = 1;
int j = i - 1;
while (i < strlen(match)) {
if (match[i] == match[pNext[j]]) {
pNext[i] = pNext[j] + 1;
i++;
j = i - 1;
}
else if (pNext[j] == 0) {
pNext[i] = 0;
i++;
j = i - 1;
}
else {
j = pNext[j] - 1;
}
}
return pNext;
}
int KMP(const char* src, const char* match) {
if (src == NULL || match == NULL) return -1;
//获得Next数组
int* pNext = GetNext(match);
//匹配
int i = 0;
int j = 0;
while (i < strlen(match) && j < strlen(src)) {
if (src[i] == match[j]) {
i++;
j++;
}
else {
//匹配串跳转
if (j == 0) {
i++;
}
else {
j = pNext[j - 1];
}
}
}
if (j == strlen(match))
{
return i - j;
}
else {
return -1;
}
}
int main() {
printf("%d\n", KMP("abcabcgweu3abcabcdusabcabcsfh", "abcabc"));//测试样例
return 0;
}
4. 2 番目に大きな探索問題のサンデーアルゴリズム
1. サンデーアルゴリズムの役割
KMP アルゴリズムは、別の文字列 (メイン文字列) 内の文字列 (文字列) の位置 (最初の要素の位置) を見つけるために使用されます。
2. 日曜日の実現
1. まず inr 型の配列を申請します。 次に 256 個のスペースを使用します (合計 256 文字なので、長さに制限のある配列を定義できます)
1. 配列を適用した後、配列内のすべての要素を -1 に代入します。
2. 部分文字列を 1 回走査し、配列内の要素に値を代入し、部分文字列内で最初に出現する部分文字列内の各要素の添字を右から左に保存します。
2. サブ文字列とメイン文字列を一致させます。
1. メイン文字列とサブ文字列をトラバースするための 2 つの変数と、メイン文字列がサブ文字列と一致するたびに添え字を検索するためのタグ変数を定義します。
2. メイン文字列とサブ文字列を照合します。それらが同じである場合は、次の文字列に進みます。同じでない場合、サブ文字列は先頭から始まり、メイン文字列は k の添え字に k の長さを加えたものになります。部分文字列を取得し、現在取得されている文字を減算します。Next 配列の添え字として機能する値が始まります。
3. 部分文字列の走査が終了するか、主文字列の走査が完了するまで、終了します。
3.日曜日のコードは次のとおりです。
//此代码是使用c++写的
#include <iostream>
#include <string>
using namespace std;
int Next[256];//申请一个Next数组,用来存匹配串中各个元素的下标
void funzhi(string a) {//初始化Next数组
for (int i = 0; i < a.size(); i++) {
Next[a[i]] = i;
}
}
int peidui(string zhu, string pi) {//进行配对
int i = 0;//主串
int j = 0;//匹配串
int length = pi.size();//匹配串长度
int k = 0;//用来标记匹配串在主串中首元素的下标
while (1) {
if (zhu[i] != pi[j]) {//如果主串元素与匹配串元素不相同
if (k + length >= zhu.size()) {//如果超出了主串的范围
return -1;
}
k = k + length - Next[zhu[k + length]];
i = k;
j = 0;
}
else {//如果主串元素与匹配串元素相同
i++;
j++;
}
if (j >= pi.size()) {//如果子串遍历完了
return k;
}
}
}