소프티어의 "성적 평균" 문제를 풀다가 사용했던 2차원 배열 동적 할당에서 어이없는 오류를 냈다.
기본 of 기본인데.. 이 참에 한번 짚고 넘어간다!
✅ 배열 동적 할당
✔ 1차원 배열을 동적 할당 시
//int 배열을 받는다고 가정하겠습니다.
int N=100;
int *arr = new int[N];
//크기가 100인 int타입의 배열을 동적 할당해주었습니다. arr이라는 이름으로요.
✔ 2차원 배열을 동적 할당 시
//동일하게 int 타입의 배열을 생성하겠습니다.
int N = 100;
int **arr = new int*[N];
//1차원과 다른 점은 바로 이 부분입니다. arr을 2차원으로 생성한다면, 먼저 1차원 포인터 배열을 가리키도록 해야겠죠?
for(int i=0; i<N; i++){
arr[i] = new int[N];//그리고 각각의 1차원 포인터에 크기가 N인 배열을 가리키도록 해주어야 2차원 형태가 됩니다.
}
어떤 실수를 했었냐면, **arr = new int[N][N]; 이렇게 해버린 것이다.. 뒤에 [N][N]은 정적 배열을 생성할 때 하는 것인데.. 이런 실수를 더이상 하지말자!!!!!
이 문제는 처음에 c++로는 2중 for문을 돌면서, 배열에서 첫번째 전화번호를 기준으로 시작하여, 다른 전화번호들 중 기준이 되는 전화번호보다 길이가 작으면 continue로 건너 뛰고, 그렇지 않으면, substr을 사용해 기준 전화번호 길이만큼 잘라서 비교한 후, 문자열이 동일하면 false를 반환하는 방식으로 접근했다.
이렇게 하면 테스트 케이스는 다 맞지만, 효율성에서 떨어지게 된다. 당연히 무식하게 2중 for문으로 일일이 확인하기 때문에 복잡도가 O(n^2)일 수 밖에 없다.
문제의 카테고리에서 주어진 방식대로 해시 알고리즘을 사용해서 풀면 효율성 문제를 해결할 수 있지만, 사실 해시 알고리즘을 어떻게 사용하는지 몰랐기 때문에, 다른 사람의 코드를 보고 참고하여 먼저 정렬을 이용해 더 쉽게 풀이하였다.
c++ / sort 함수와 1중 for문으로 풀기
string 타입의 배열 phone_book을 <algorithm> 헤더에 있는 기본 정렬 함수인 sort()를 통해 정렬한다.
숫자로 표현된 문자열의 경우 사전식으로, 각 문자열의 첫번째 값부터 비교한다.
첫번째 값들이 다 동일하면 두번째 값을 비교한다.
즉 숫자 그 자체가 큰지가 아니라, 앞에 문자열부터 각 숫자가 작은 것 부터 정렬하는 방식이다
예) "12" "14" "112" 가 있으면, 112, 12, 14 순으로 정렬 된다.
첫번째 1은 모두 같고, 두번째 값이 1,2,4순이기 때문이다.
따라서 이렇게 정렬을 먼저 해 놓으면, 자연스럽게 접두사가 될 확률이 높은 문자열이 앞에 위치하게 되고, 해당 접두사를 가지는 문자열은 무조건 그 문자열의 다음에 정렬될 것이기 때문에, 이 방법은 1중 for문으로도 인접한 문자열에 대해 한번씩만 비교하면 된다.
sort함수에 배열의 첫번째 요소와, 배열의 마지막 요소를 인자로 넣어주면, 자동으로 정렬된다.
1중 for문을 통하여 string 문자열 s에는 현재 접근하는 phone_book의 전화번호 바로 다음에 위치한 전화번호를, 접두사 길이 만큼 잘라 (substr을 사용) 저장한다. 이때 c++에서는 substr(시작 인덱스, 자르고 싶은 만큼의 문자열 크기) 이므로 이에 유의한다.
그래서 현재 접두사 후보의 값과 s가 일치한다면 false를 반환하도록 answer에 설정해준다.
사실상 해시 알고리즘으로 푸는 의도의 문제이긴 하지만, 실제 코테에서는 이 방법을 꼭 사용하라는 명시가 없기 때문에, 위와 같이 효율적인 코드가 생각이 난다면 당연히 사용해도 좋다.
그러나 해시 알고리즘을 이번 기회에 알고 넘어 가기 위해 java를 이용해서 한번 더 풀어보았다.