문자열은 문자의 배열이기 때문에 수열과 비슷한 원리로 해결할수도있습니다 마찬가지로 문자열과 비슷한원리로 수열 문제를 해결할 수도있습니다.


문자열은 알고리즘문제에서 출제가 꽤 많이 됩니다. 프로그래머스에서 보는 알고 시험들이나 등등이거의 문자열문제가 많이 나오는 느낌입니다.


1. 문자열 탐색

show me the money 에서 mon을 찾으세요 하는 문제가나오면

show me the money자체에 "mon"이란 단어를 하나씩 비교하여

sho -> mon    X

 how -> mon    X

   ow -> mon    X 

이런식으로 비교할 수 있습니다. 물론 짧고 적절한 문자열에서는 이게 구현하는게 편하기때문에 이렇게 구현해도 괜찮다고 봅니다.

우선 mon이 하나밖에 없으면 재미없으니까 중간에 monkey를 끼도록 합니다.

show me the monkey money.

로 코드를 한번 구현해보았습니다,

위에서 설명한 가장 기본적인 문자열 탐색입니다. 물론 입력과 출력은 시험보는것 마냥.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
string sentence;
string word;
void searchword(string sen, string words) {
    int k = 0// 탐색된 개수를 저장합니다. 여기서는 문장에포함된 mon개수입니다.
    for (int j = 0; j < sen.size(); j++) { //문장크기만큼 비교합니다.
 
        for (int i = 0; i < words.size(); i++) { //단어크기만큼 비교합니다.
 
            if (sen[j+i] == words[i]) {   //단어의시작점부터 비교대상을 함꼐 한글자씩 옆으로 움직입니다.
                if (i == words.size() - 1) {
                    k++;
                    break;
                }
                continue;
            }
            else break;
            
        }
    }
    cout << k;
}
int main() {
    getline(cin, sentence);
    getline(cin, word);
 
    searchword(sentence, word);
    
}
cs



이렇게 풀어주었습니다. searchword 안의 sen[j+i]만 이해하면 끝날듯..

하지만 몇번나오는지가 아니라 존재하는지 알고싶다? 그러면 string 에서 제공하는 find 를 사용하면됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
string sentence;
string word;
int k = 0;
int main() {
    getline(cin, sentence);
    getline(cin, word);
    
    k=sentence.find(word);
    k > 0 ? cout << "존재" : cout << "안존재";
}
cs

find는 처음으로 탐색된 문자의 첫번째 자리를 반환합니다.

만약없다면 -1을 리턴하는걸 이용하여서

이런식으로 코드를 짜주었습니다.


find함수는 엄청유용합니다.

검색하는데 자주쓰이는데 아래와 같은 인자들이 쓰입니다.


    find(const basic_string& str, size_type pos = 0) const;

str - 찾고자 하는 문자열

pos- 검색시작할 위치


find(const CharT* s, size_type pos, size_type count) const;

s- 찾고자 하는 문자열 포인터

pos- 검색시작할 위치

count - 찾고자하는 문자열 길이


근데 이 find가 string헤더에도있고 algorithm헤더에도 있다는사실.

배열에서 사용할때에는 인자로 배열의 시작점,끝점, 찾을값 을 넣어줘야하며 모두 주소값입니다. 물론 찾을값빼고


1
2
3
4
5
6
7
8
9
10
11
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int good[10= { 10,9,8,7,6,5,4,3,2,1 };
int *answer;
int main() {
    answer = find(good, good+10,12);
    answer == good + 10 ? cout << "못찾음" : cout << "찾음";
    cout << endl;
}
cs

숫자로 코드 예를 하나 들어보겠습니다. find마지막인자인 찾을값에 12가 들어갔으므로 못찾음으로 결과가 출력됩니다.


find는 결국 해당값을 찾으면 찾은위치 주소를 리턴하게되고, 못찾았으면 가장끝점의 위치를 리턴합니다.

그래서 find의 결과값을 가장끝점의위치인 good+10과 비교해서 같으면~ 못찾은거고, 다르면 찾은거고. 물론 리턴값으로는 그 주소값이 나옵니다.


어 ? 그러면 find쓰면서 주소값 적절히 빼주면서 카운트 세면면 갯수를 찾을수 있겟네? 라고 생각할수도 있지만 갯수를 세는 함수도 있습니다.


1
2
3
4
5
6
7
8
9
10
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int good[10= { 10,9,8,7,6,5,4,3,3,13 };
int answer;
int main() {
    answer = count(good, good+10,3);
    cout << answer << endl;
}


count 함수를 쓰게되면 인자로 똑같이 시작점, 끝점, 찾을것 을 넣게됩니다.

알고리즘헤더에서는 find_if 와 count_if 도 제공합니다.

둘다비슷하니 find_if만 설명하겠습니다.

find_if는 조건 검색입니다.

find는 특정한값을 찾는다고 생각하면 find_if는 말그대로 조건에 만족하는 값을 찾아줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;
int good[10= { 10,9,8,7,6,5,4,3,3,13 };
int *answer = good;
bool jogun(int n) {
    return (n > 5);
}
int main() {
    while (answer != good + 10) {
        answer = find_if(answer, good + 10, jogun);
        cout << answer-good << endl;
        answer++;
    }
}
cs

이렇게 한번 구현해 보았습니다. find_if 는 매개변수에서 값대신 함수 포인터를 넘겨줍니다. 이 함수는 매개변수로 해당 자료형을 받고

리턴형은 bool값이 됩니다. 저는 이름을 jogun(조건) 이라고 지었습니다. true가 리턴되면 조건에 맞다는 뜻입니다.

answer에 시작위치를넘겨주고 하나씩 증가시키면서 위치를 찾도록 시켜보았습니다.


이렇게 5보다 큰 숫자들의 위치가 출력됩니다.

카운트도 똑같이 쓰면 조건에 맞게 카운트를 할수 있습니다.


문자열검색으로 다시 돌아가봅니다.

show me the money 에서 mon을 찾으세요 하는 문제가나오면

show me the money자체에 "mon"이란 단어를 하나씩 비교하여

sho -> mon    X

 how -> mon    X

   ow -> mon    X 

이런식으로 검색할경우. 처음 s위치에서 mon만큼 h위치에서 mon만큼

빅오표기법으로할때 총 O(전체문자열 * 찾을문자열) 이 될것입니다.

하지만 KMP알고리즘을 사용하게되면 O(전체문자열+찾을문자열) 로 처리할 수 있습니다.


abckkkabcd

에서 abcd를 찾는다고 생각해봅시다.

원래방식대로라면 


abckkkabcd

abcd

abckkkabcd

 abcd

abckkkabcd

   abcd

이런 차례로 검색하게됩니다. 

아니 abck가나와서 다른거면

abck 순서 다넘기고 kkab부터 검색하면되는거아니냐? 에서 착안된것입니다.

다음 글에서 다루도록 하겠습니다. 



'재미있는공부이야기 > 알고리듬' 카테고리의 다른 글

백준 2178번 미로찾기  (0) 2019.02.20
KMP 알고리즘  (0) 2019.02.15
2장. 정렬  (0) 2019.02.09
백준 2846번 오르막길  (0) 2019.02.09
백준 2920번 음계  (0) 2019.02.07

+ Recent posts