위 글은 큰돌의 터전 님의 강의자료를 참조해서 정리하고 제가 알고리즘을 풀면서 더 추가적으로 사용할 만한 내용들을 정리한 글입니다.
알고리즘 풀이 강의로 큰돌의 터전님의 강의 강력 추천드립니다.
강의 링크
알고리즘 풀 때 string을 써야하는 이유
입력이 한글이라면 코딩 테스트 특성상 영어만을 입력으로 주지 않을 수가 있다.
만약 char 형 배열을 사용한다면 영어 입력인 경우 문제가 없지만 한글인 경우 한글은 한 글자당 3바이트라서 원하는 출력을 유도할 수 없을 수 있다.
string에서 많이 사용하는 메서드 모음
#include <bits/stdc++.h>
using namespace std;
int main(){
string a = "love is";
a += " pain!";
a.pop_back();
cout << a << " : " << a.size() << "\n";
cout << char(* a.begin()) << '\n';
cout << char(* (a.end() - 1)) << '\n';
// string& insert (size_t pos, const string& str);
a.insert(0, "test ");
cout << a << " : " << a.size() << "\n";
// string& erase (size_t pos = 0, size_t len = npos);
a.erase(0, 5);
cout << a << " : " << a.size() << "\n";
// size_t find (const string& str, size_t pos = 0);
auto it = a.find("love");
if (it != string::npos){
cout << "포함되어 있다." << '\n';
}
cout << it << '\n';
cout << string::npos << '\n';
// string substr (size_t pos = 0, size_t len = npos) const;
cout << a.substr(5, 2) << '\n';
return 0;
}
/*
love is pain : 12
l
n
test love is pain : 17
love is pain : 12
포함되어 있다.
0
18446744073709551615
is
*/
C++
복사
+=
메서는 아니며 문자열에서 문자열을 더할 때 보통 += 를 써서 문자열 또는 문자를
더합니다. push_back()라는 메서드가 있지만 이는 문자 밖에 더하지 못해 보통 += 를
씁니다.
begin()
문자열의 첫번째 요소를 가리키는 이터레이터를 반환합니다.
end()
문자열의 마지막 요소 그 다음을 가리키는 이터레이터를 반환합니다.
참고로 begin()과 end()는 자료구조인 vector, Array, 연결리스트, 맵, 셋에서도 존재하며
똑같은 의미를 지닙니다.
back()
string의 마지막 인자를 반환합니다.
front()도 존재하지만 그것은 str[0]으로 접근이 가능하므로 딱히 사용이 잘 안되지만 back()은 상당히 유용하게 사용할 수 있습니다. *(str.end()); 이렇게 접근하지 맙시다.
size()
문자열의 사이즈를 반환합니다. O()의 시간복잡도를 가집니다.
insert(위치, 문자열)
특정위치에 문자열을 삽입합니다. O(n)의 시간복잡도를 가집니다.
erase(위치, 크기)
특정위치에 크기만큼 문자열을 지웁니다. O(n)의 시간복잡도를 가집니다.
pop_back()
문자열 끝을 지웁니다. O(1)의 시간복잡도를 가집니다.
find(문자열)
특정 문자열을 찾아 위치를 반환합니다. 만약 해당 문자열을 못 찾을 경우 string::npos를
반환하며 O(n)의 시간복잡도를 가집니다.
string::npos는 size_t 타입의 최대값을 의미합니다. size_t 타입의 최대값은 OS에 따라
달라지며 64비트 운영체제라면 64비트 부호가 없는 최대정수, 32비트 운영체제라면 32비트
부호가 없는 최대 정수값을 가집니다. 필자의 컴퓨터는 64비트 운영체제이기 때문에
18446744073709551615라는 값을 가집니다.
substr(위치, 크기)
특정 위치에서 크기만큼의 문자열을 추출합니다. O(n)의 시간복잡도를 가집니다.
string 도 배열처럼 쓸 수가 있습니다.
int main()
{
string s = "123";
s[0]++;
cout << s;
}
/*223*/
C++
복사
아스키 코드 값
97 : a , 65 : A , 알파벳 26개
STL string활용
reverse()
문자열 string은 reverse()라는 메서드를 지원하지 않습니다. 문자열을 거꾸로 뒤집고 싶다면
STL에서 지원하는 함수인 reverse()를 쓰면 됩니다.
template <class BidirectionalIterator> void reverse (BidirectionalIterator
first, BidirectionalIterator last);
C++
복사
reverse() 함수는 void 타입으로 아무것도 반환하지 않습니다. 그리고 원본 문자열도
바꿔버립니다
다음 코드처럼 구축이 가능하며, a.begin() + 3 처럼 시작위치를 바꿔 뒤집고 싶은 부분만을
바꿀 수 있습니다.
#include <algorithm>
#include <string>
using namespace std;
int main(){
string a = "It's hard to have a sore leg";
reverse(a.begin(), a.end());
cout << a << '\n';
reverse(a.begin(), a.end());
cout << a << '\n';
reverse(a.begin() + 3, a.end());
cout << a << '\n';
return 0;
}
/*
gel eros a evah ot drah s'tI
It's hard to have a sore leg
It'gel eros a evah ot drah s
*/
C++
복사
split()
코딩테스트에서는 문자열을 split() 하는 로직이 많이 등장합니다.split()함수란 다른
프로그래밍 언어에서도 문자열을 특정 문자열을 기준으로 쪼개어서 배열화시키는 함수라는
의미로 사용되는데 C++에서는 STL에서 split() 함수를 지원하지 않습니다. 그래서
만들어야 합니다.
참고로 split()은 0주차개념강의에서 설명합니다. 강의를 보면서 설명을 보는 것을
추천합니다.
보통 다음과 같이 구현합니다. 시간복잡도는 O(n)의 시간복잡도를 가집니다.
#include <bits/stdc++.h>
using namespace std;
vector<string> split(string input, string delimiter)
{
vector<string> ret;
long long pos = 0;
string token = "";
while ((pos = input.find(delimiter)) != string::npos)
{
token = input.substr(0, pos);
ret.push_back(token);
input.erase(0, pos + delimiter.length());
}
ret.push_back(input);
return ret;
}
int main()
{
string s = "안녕하세요 큰돌이는 킹갓제너럴 천재입니다 정말이에요!", d = " ";
vector<string> a = split(s, d);
for(string b : a) cout << b << "\n";
}
/*
안녕하세요
큰돌이는
킹갓제너럴
천재입니다
정말이에요!
*/
C++
복사
코드 설명
input에서 delimiter를 찾습니다. 못 찾을 때까지는 이 루프는 반복됩니다.
while ((pos = input.find(delimiter)) != string::npos)
C++
복사
그 다음 이 추출한 문자열을 ret이란 배열에 집어 넣습니다.
ret.push_back(token);
C++
복사
그리고 앞에서 부터 문자열을 지웁니다. abcdabc에서 d가 delimeter이라면 pos = 3,
delimeter의 사이즈는 1이기 때문에 앞에서 부터 4의 크기의 문자열을 제거해 abc만 남게
됩니다.
input.erase(0, pos + delimiter.length());
C++
복사
범위기반 for 루프
앞의 코드를 보면 범위기반 for루프가 있는 것을 볼 수 있는데 C++11부터 범위기반 for
루프가 추가되어서 이를 쓸 수 있습니다.
for ( range_declaration : range_expression )
loop_statement
C++
복사
다음 코드는 vector a내의 있는 요소인 string타입의 요소를 탐색한다는 코드입니다.
for(string b : a) cout << b << "\n";
C++
복사
이 코드와 같은 의미 입니다.
for(int i = 0; i < a.size(); i++) cout < a[i] << "\n";
C++
복사
코드 예시
#include<bits/stdc++.h>
using namespace std;
string a[2] = {"out of time", "i love you"};
int main(){
for(string b : a) cout << b << '\n';
for(int i = 0; i < 2; i++) cout << a[i] << "\n";
}
/*
out of time
i love you
out of time
i love you
*/
C++
복사
atoi(s.c_str())
문자열을 int로 바꿔야 할 상황이 있습니다. 예를 들어 입력이 “amumu” 또는 0 이렇게
온다라고 했을 때 문자열, string으로 입력을 받아 입력받은 글자가 문자열인지 숫자인지
확인해야 하는 로직이 필요할 때 말이죠.
다음 코드 처럼 입력받은 문자열 s를 기반으로 atoi(s.c_str())로 쓰입니다. 이렇게 보면 만약
입력받은 문자열이 문자라면 0을 반환하고 그게 아니라면 숫자를 반환합니다.
#include <bits/stdc++.h>
using namespace std;
int main(){
string s = "1";
string s2 = "amumu";
cout << atoi(s.c_str()) << '\n';
cout << atoi(s2.c_str()) << '\n';
return 0;
}
/*
1
0
*/
C++
복사
string 활용
공백까지 한번에 받기
기본적으로 cin은 공백까지만 입력을 받기 때문에 공백을 string으로 한번에 받으려면 함수를 사용해줘야 한다.
1. getline함수 (#include <string>)
원형
getline(istream& is, string str);
getline(istream& is, string str, char dlim);
C++
복사
사용예시
int main() {
string s;
getline(cin, s);
cout << s;
}
C++
복사
알아서 공백을 포함하여 문자열을 받는다. 즉 개행 전까지 받는 함수이다. string 헤더에 포함되어 있다.
string을 사용하는 경우에는 왠만하면 이 함수를 사용하는 것이 좋은 것 같다. 지정한 문자를 만나기 전까지 쭉 읽어서 string 객체에 저장을 해준다.
2. cin.getline(#include <iostream>)
원형
cin.getline(char str, streamsize n);cin.getline(char str, streamsize n, char dlim);
C++
복사
사용예시
int main() {
char s[100];
cin.getline(s,100,'\n');
cout << s;
}
C++
복사
C언어 스타일의 문자열을 입력 받을 때 사용하는게 좋다. (char형 배열이나 문자열 끝이 널 문자인 경우)
크기를 n으로 지정해주면 n-1개의 문자를 읽어와서 배열에 넣어주게 된다.
구분자를 지정해주지 않으면 기본으로는 개행까지 읽어준다.
cin같은 경우 입력을 계속 받아주게 되면 개행이 계속 버퍼에 남아있어서 cin.ignore() 를 사용해야합니다!
왠만하면 string에 getline을 써줍시당.