코딩테스트 문제풀이를 하며 찾아보았던 내용을 정리했다.
표준 라이브러리 <algorithm>
에는 min()
, max()
함수가 있어 주어진 두 수 중 최솟값과 최댓값을 리턴한다.
int a = 1;
int b = 2;
int result = min(a, b); // 2 반환
자료형* 포인터명 = 할당값
&변수명
이므로 이를 가리키려면 할당값
에 &변수명
으로 사용&포인터명
으로 얻을 수 있음*포인터명
으로 역참조int num = 1;
int* numPtr = #
cout << "num: " << num << endl;
cout << "&num: " << &num << endl;
cout << "numPtr: " << numPtr << endl;
cout << "&numPtr: " << &numPtr << endl;
cout << "*numPtr: " << *numPtr << endl;
// num: 1
// &num: 005AF868
// numPtr: 005AF868
// &numPtr: 005AF85C
// *numPtr: 1
기존에 알고 있던 &
비트 연산, 조건 식에서 &&
으로 AND 의미, 그리고 메모리의 주소 값을 가리키는 &변수
쓰임 말고도 하나가 더 있다.
&
는 변수의 참조자, 즉 별명을 붙이는 기능을 한다. 자료형& 별명 = 변수명
으로 할당하면 해당 변수를 앞으로는 '별명'으로 부르겠다는 이야기이다.
int a;
int& b = a;
b = 3;
cout << "a: " << a << ", b: " << b << endl; // a: 3, b: 3 출력
미리 벡터의 크기를 지정하거나, 특정 값으로 선언과 동시에 초기화하고 싶다면 vector<자료형> 벡터명(크기, 값)
으로 선언한다. 만약 값
부분을 생략하고 크기
만 입력한다면 0으로 초기화된다. 초기화 없이 개수만 지정하려면 vector<자료형> 벡터명[크기]
로 선언할 수 있다.
2차원 벡터를 크기 지정해 선언하려면, 한 행이 한 벡터가 되므로 초기화 하는 값으로서 안쪽 벡터를 넣어주면 된다.
int width = 5;
int height = 3;
vector<string> row(width, "*");
vector<vector<string>> vec(height, row);
for (vector<string> row : vec)
{
for (string elem : row)
cout << elem << " ";
cout << endl;
}
/*
출력결과----------------------
* * * * *
* * * * *
* * * * *
*/
벡터의 요소 하나하나를 보고 싶다면 인덱스로 vec[1]
처럼 보는 방법 말고도, 파이썬처럼 범위 기반 for 문 형태를 사용할 수 있다. 단 이때는 요소 값을 직접 변경할 수는 없다. for(자료형 요소이름 : 벡터명)
으로 쓴다. 벡터의 요소 하나하나를 요소이름
으로 한다는 뜻이다.
vector<int> vec = {0, 1, 2, 3};
for(int elem : vec)
cout << elem << " "; // 0 1 2 3 출력
다른 방법으로는 iterator(이터레이터, 반복자)를 이용할 수도 있다. 반복자의 값을 참조할 때는 *
을 사용한다. 이렇게는 값을 변경할 수 있다.
vector<int> vec = {0, 1, 2, 3};
for (int iter = vec.begin(); iter != vec.end(); iter++) {
cout << *iter << " ";
}
기본적으로 sort(시작 반복자, 끝 반복자)
로 정렬 가능하다.
2차원의 경우에 sort(행 벡터의 시작 반복자, 행 벡터의 끝 반복자)
로 각 행(큰 벡터의 요소)에 대해 반복하면 된다.
// 1차원 벡터
vector<int> vec1 = {4, 2, 1, 5};
sort(vec1.begin(), dungeons.end());
// 2차원 벡터
vector<vector<int>> vec2D(4, vector<int> vec1D(3));
for (int i = 0; i < vec2D.size(); i++)
{
sort(vec2D[i].begin(), vec2D[i].end());
}
[True일 때 값] if [조건] else [False일 때 값]
[조건] ? [True일 때 값] : [False일 때 값]
순열(permutation)은 서로 다른 n개에서 r개를 뽑아 줄을 세웠을 때 가능한 모든 경우의 수를 말하는데, 표준 라이브러리 <algorithm>
에는 next_permutation
으로 다음 순열을 반환하는 기능을 지원한다. 원형은 아래와 같다.
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last);
즉, 배열이나 벡터 등의 컨테이너의 시작 반복자와 끝 반복자를 각각 인자로 넣어준다. 다음 순열이 있다면 그 컨테이너의 순서를 해당 순열의 순서로 바꾸고 true를 반환하며, 순열이 없다면 false를 반환한다.
이때 주의할 것은 next_permutation
은 컨테이너가 오름차순으로 정렬된 값을 가져야 하고 오름차순으로 순열을 생성하며, 중복을 제외하고 순열을 만든다는 것이다.
숫자 계산의 결과가 해당 자료형의 표현 가능 범위를 벗어나면 Overflow가 발생한다.
정수형인 int
는 부터 까지의 범위를 표현할 수 있으므로 100,000 X 100,000을 계산하면 오버플로우가 발생한다.
이를 해결하기 위해 더 큰 범위의 자료형을 곱해주면 그 범위의 계산으로 이루어진다. 서로 다른 자료형을 연산할 때는 더 큰 범위를 가지는 자료형을 기준으로 계산되기 때문이다.
1LL
중 LL
은 long long int
의 준말로 1LL
은 1을 long long int의 자료형으로 나타낸다는 의미이다. 따라서 1LL * 100,000 * 100,000
을 하면 int가 아니라 long long의 범위로 계산이 이루어져 오버플로우가 일어나지 않는다. 단, 연산은 좌에서 우로 이루어지므로 100,000 * 100,000 * 1LL
이면 앞서 int 범위 내에서 여전히 오버플로우가 발생하므로 순서에 주의한다.
2차원 리스트를 선언하는 방법 중 두 가지가 있는데, 한 예로 0으로 초기화된 5 X 5 리스트를 만든다고 하자.
arr1 = [[0] * 5] * 5
arr2 = [[0 for i in range(5)] for j in range(5)]
둘 모두 아래와 같은 모양을 가진다.
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
여기서 (1, 2)의 값을 1로 바꾼다고 하자. 이때 결과는 아래와 같이 달라진다.
# 방법1
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
# 방법2
[0, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
이는 [방법1]의 경우 얕은 복사가 되기 때문이다. 자세한 원리는 아래 참고문헌 링크를 참조한다.
heapq.heappush(힙 리스트, 요소값)
heapq.heappop()
힙리스트[0]
인 것이다.heapq.heapify(리스트)