Algorithm/Programmers

[프로그래머스] [2020카카오공채] 가사 검색

1일1코딩 2020. 2. 29. 15:58

https://programmers.co.kr/learn/courses/30/lessons/60060

 

코딩테스트 연습 - 가사 검색 | 프로그래머스

 

programmers.co.kr

 

며칠전 trie 탐색을 공부하고 문제를 풀었던 적이 있었는데, 이 문제를 보고 딱 생각이 나서 적용시켜보았다.

 

정확성은 다 Pass를 했으나, 효율성에서 0이였다.

 

효율성 0 코드

더보기
#include <string>
#include <vector>
#include <string.h>
#define ALPHABET 26
using namespace std;
struct trie {
	trie *next[ALPHABET];
	int count[ALPHABET];
	int finish;
	int total;
	trie() : finish(0), total(0){
		memset(next, NULL, sizeof(next));
		memset(count, 0, sizeof(count));
	}
	
	~trie() {
		for (int i = 0; i < ALPHABET; i++) {
			if (next[i] != NULL) {
				delete next[i];
			}
		}
	}

	void insert(const char *str) {
		total++;
		if (*str == '\0') {
			finish = 1;
			return;
		}
		int cur = *str - 'a';
		if (next[cur] == 0) {
			next[cur] = new trie();
		}
		count[cur]++;
		next[cur]->insert(str + 1);
	}

	trie* find(const char *str) {
		if (*str == '\0') {
			return this;
		}
		int cur = *str - 'a';
		if (next[cur] == NULL) {
			return 0;
		}
		return next[cur]->find(str + 1);
	}

	int findPatternKey(const char* str) {
		if (*str == '\0') {
			return finish;
		}
		if (*str == '?') {
			int sum = 0;
			for (int i = 0; i < ALPHABET; i++) {
				if (next[i] == NULL) continue;
				sum += next[i]->findPatternKey(str + 1);
			}
			return sum;
		}
		else {
			int cur = *str - 'a';
			if (next[cur] == NULL) {
				return 0;
			}
			return next[cur]->findPatternKey(str + 1);
		}
	}
};

vector<int> solution(vector<string> words, vector<string> queries) {
	vector<int> answer;
	trie *root = new trie();
	for (int i = 0; i < words.size(); i++) {
		root->insert(words[i].c_str());
	}
	for (int i = 0; i < queries.size(); i++) {
		answer.push_back(root->findPatternKey(queries[i].c_str()));
	}
	return answer;
}

 

 

효율성 통과한 소스

 

기존에는 한 트리에 모든 문자열이 담겨있었다면, 이번에는 문자열 길이로 루트배열을 만들어 해당 크기에서만 찾는다.

 

'?' 키워드가 앞에 앞에 있는지 뒤에 있는지를 체크해서 더 효율을 높이려 reverseRoot를 만들었다.

 

?가 앞에 있으면 reverseRoot를, 뒤에 있으면 기존 root를 찾도록 하였다.

 

소스보기

더보기
#include <string>
#include <vector>
#include <string.h>
#include <algorithm>
#define ALPHABET 26
using namespace std;
struct trie {
	trie *next[ALPHABET];
	int finish;
	int total;
	trie() : finish(0), total(0){
		memset(next, NULL, sizeof(next));
	}
	
	~trie() {
		for (int i = 0; i < ALPHABET; i++) {
			if (next[i] != NULL) {
				delete next[i];
			}
		}
	}

	void insert(const char *str) {
		if (*str == '\0') {
			finish = 1;
			return;
		}
		int cur = *str - 'a';
		if (next[cur] == 0) {
			next[cur] = new trie();
		}
		
		next[cur]->total++;
		next[cur]->insert(str + 1);
	}

	trie* find(const char *str) {
		if (*str == '\0') {
			return this;
		}
		int cur = *str - 'a';
		if (next[cur] == NULL) {
			return 0;
		}
		return next[cur]->find(str + 1);
	}

	int findPatternKey(const char* str) {
		if (*str == '?') {
			int sum = 0;
			for (int i = 0; i < ALPHABET; i++) {
				if (next[i] == NULL) continue;
				sum += next[i]->total;
			}
			return sum;
		}
		else {
			int cur = *str - 'a';
			if (next[cur] == NULL) {
				return 0;
			}
			if (*(str + 1) == '?') {
				return next[cur]->total;
			}
			return next[cur]->findPatternKey(str + 1);
		}
	}
};

trie* root[10001];
trie* reroot[10001];
vector<int> solution(vector<string> words, vector<string> queries) {
	vector<int> answer;
	memset(root, NULL, sizeof(root));
	memset(reroot, NULL, sizeof(reroot));
	for (int i = 0; i < words.size(); i++) {
		int wordsize = words[i].size();
		if (root[wordsize] == NULL) {
			root[wordsize] = new trie();
			reroot[wordsize] = new trie();

			root[wordsize]->insert(words[i].c_str());
			
			reverse(words[i].begin(), words[i].end());
			reroot[wordsize]->insert(words[i].c_str());
		}
		else {
			root[wordsize]->insert(words[i].c_str());
			
			reverse(words[i].begin(), words[i].end());
			reroot[wordsize]->insert(words[i].c_str());
		}
	}
	for (int i = 0; i < queries.size(); i++) {
		if (root[queries[i].size()] == NULL) {
			answer.push_back(0);
		}
		else {
			int front = queries[i][0] == '?' ? 1 : 0;
			if (front) {
				reverse(queries[i].begin(), queries[i].end());
				answer.push_back(reroot[queries[i].size()]->findPatternKey(queries[i].c_str()));
			}
			else {
				answer.push_back(root[queries[i].size()]->findPatternKey(queries[i].c_str()));
			}
		}
	}
	return answer;
}