본문 바로가기
자료구조와 알고리즘/[Inflearn_큰돌] 10주 완성 C++ 코딩테스트

1주차-5. 9996번: 한국이 그리울 땐 서버에 접속하지

by 헛둘이 2022. 9. 27.

 

9996번: 한국이 그리울 땐 서버에 접속하지

  • 요약하자면 첫 입력으로 입력 횟수가 주어지고 두 번째 입력으로 패턴이 주어짐
  • 패턴은 a*b 와 같은 식으로 되어 있는데
  • 이후 입력 횟수에 따라 입력되는 문장들이 패턴에 부합하는지 체크해서 부합하면 DA, 아니면 NE를 출력하는 문제

 

 

 

 

먼저 무작정 풀어보기
#include <iostream>
#include <vector>
#include <string>

int main()
{
	int n = 0;
	std::cin >> n;

	std::string patt;
	std::cin >> patt;

	std::string temp;
	std::vector<std::string> res;
	
	for (int i = 0; i < n; i++)
	{
		std::cin >> temp;

		if (temp.front() == patt.front() &&
			temp.back() == patt.back())
			res.push_back("DA"); 
		else
			res.push_back("NE");
	}

	for (int i = 0; i < res.size(); i++)
	{
		if (i == res.size() - 1){
			std::cout << res[i];
			break;
		}
			
		std::cout << res[i] << std::endl; 
	}	
}

 

  • 맞왜틀(맞는데 왜 틀림)이 많이 나왔던 문제
  • 상식이라고 생각했던 부분들에 뒤통수를 쎄게 맞았다.
  • 입력 예문에서 a*b라고 되어 있길래 * 문자 앞 뒤로 한 글자만 오는 줄 착각했던 게 화근이었다.

더닝 크루거의 우매함에 봉우리에 아직 오르지도 못했는데..거만했다..

  • 맨 위는 와일드카드 앞 뒤로 한 글자만 오는 게 아니라는 생각이 문득 들어서 2차시도 한 흔적이다.
#include <iostream>
#include <vector>
#include <string>

std::vector<std::string> split(std::string text, std::string delimiter)
{
	std::string temp;
	int offset = 0;
	std::vector<std::string> ret;

	while ((offset = text.find(delimiter, 0)) != std::string::npos)
	{
		temp = text.substr(0, offset);
		ret.push_back(temp);
		
		text.erase(0, offset + delimiter.length());
	}

	ret.push_back(text);
	return ret;
}

int main()
{
	int n = 0;
	std::cin >> n;

	std::string patt;
	std::cin >> patt;

	std::vector<std::string> words = split(patt, "*");
	
	std::string temp;
	std::vector<std::string> res;
	
	for (int i = 0; i < n; i++)
	{
		std::cin >> temp;
		
		if (words[0] == temp.substr(0, words[0].size()) &&
			words[1] == temp.substr(temp.size() - words[1].size()))
			res.push_back("DA");
		else
			res.push_back("NE");
	}

	for (auto& s : res)
		std::cout << s << std::endl;
}
  • 2차 시도 코드
  • 2차 시도는 split 함수를 사용해서 와일드 카드를 기준으로 분할한 후 앞, 뒤 값을 확인하여 비교하도록 했다.
  • 여기서는 런타임 에러가 떴다.(ㅡㅡ..)
  • 이후 큰돌님의 강의를 보고 반례 체크를 해야 한다는 사실을 깨달았다.

 

#include <iostream>
#include <vector>
#include <string>

std::vector<std::string> split(std::string text, std::string delimiter)
{
	std::string temp;
	int offset = 0;
	std::vector<std::string> ret;

	while ((offset = text.find(delimiter, 0)) != std::string::npos)
	{
		temp = text.substr(0, offset);
		ret.push_back(temp);

		text.erase(0, offset + delimiter.length());
	}

	ret.push_back(text);
	return ret;
}

int main()
{
	int n = 0;
	std::cin >> n;

	std::string patt;
	std::cin >> patt;

	std::vector<std::string> words = split(patt, "*");

	std::string temp;
	std::vector<std::string> res;

	for (int i = 0; i < n; i++)
	{
		std::cin >> temp;
		
        
        	// 반례 체크
		if (temp.size() < words[0].size() + words[1].size())
			res.push_back("NE");

		else if (words[0] == temp.substr(0, words[0].size()) &&
			words[1] == temp.substr(temp.size() - words[1].size()))
			res.push_back("DA");
		else
			res.push_back("NE");
	}

	for (auto& s : res)
		std::cout << s << std::endl;
}
  • 반례를 체크하는 이유는 ab*ab라는 패턴이 주어졌을 때 ab 라는 문장이 맞다는게 되기 때문
  • 앞으로는 쉬운 문제라도 논리적으로 말이 되는지 생각하는 습관을 들여야겠다.
  • 반례를 구하니 통과처리되었다.

 

 

 

큰돌님의 풀이
#include <iostream>
#include <vector>
#include <string>

int n;
std::string s, ori_s, pre, suf;

int main()
{
	std::cin >> n;
	std::cin >> ori_s;

	int pos = ori_s.find('*');

	pre = ori_s.substr(0, pos);
	suf = ori_s.substr(pos + 1);

	for (int i = 0; i < n; i++)
	{
		std::cin >> s;
		if (pre.size() + suf.size() > s.size()) {
			std::cout << "NE\n";
		}
		else {
			if (pre == s.substr(0, pre.size()) && suf == s.substr(s.size() - suf.size()))
				std::cout << "DA\n";
			else
				std::cout << "NE\n";
		}
	}

	return 0;
}
  • split 대신 substr을 사용하셨다.
  • substr을 통해 별 표 기준으로 앞 뒤만 자르는 방법을 왜 생각하지 못했을까
  • 나 스스로 느끼기에 처음 생각했던 방향성에 갇혀 있는 경향이 좀 있는 것 같다.

역시 내 코드가 4KB나 더 먹는다..ㅜㅜ

 

댓글