IT 프로그래밍/백준

[C++] 백준 1316번 그룹 단어 체커

기술1 2024. 4. 7. 20:12

https://www.acmicpc.net/problem/1316

 

1316번: 그룹 단어 체커

그룹 단어란 단어에 존재하는 모든 문자에 대해서, 각 문자가 연속해서 나타나는 경우만을 말한다. 예를 들면, ccazzzzbb는 c, a, z, b가 모두 연속해서 나타나고, kin도 k, i, n이 연속해서 나타나기 때

www.acmicpc.net

 

 

코드

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;


int main()
{
	int n;
	cin >> n;

	string word;
	int count = 0;
	for (int i = 0; i < n; i++)
	{
		cin >> word;
		word.erase(unique(word.begin(), word.end()), word.end());
		sort(word.begin(), word.end());
		bool isgroup = true;
		
		for (int k = 0; k < word.length()-1; k++)
		{
			if (word[k] == word[k + 1])
			{
				isgroup = false;
				break;
				
			}
		}
		if (isgroup)
			count++;
	}
	cout << count << endl;
}

해당 문제를 제가 푼 방식입니다. 바로 erase를 통해서 연속으로 중복되는 값을 없앤 다음 정렬을 해서 비교를 통해 같은 수가 나오면 소거하는 방식으로 문제를 풀었는데요. 여기에서 알아야 하는 것은 unique()의 개념과 erase()의 개념, 그리고 bool 함수의 개념입니다. 

 

먼저 word;를 string한 다음에 for문을 통해서 word를 입력받습니다. 그 string 형태의 word를 사용자가 입력하면 

 

erase(unique(word.begin(), word.end()), word.end()); 이렇게 하면 중복된 연속의 수들이 제거됩니다. 

 

unique(word.begin(), word.end())은 단어에서 중복된 연속의 수를 뒤로 빼주는 역할을 합니다. 그리고 반환값으로 중복된 값의 첫번째 값을 return해줍니다. 그렇기 때문에 erase(중복된 값의 첫번째 수, word.end())를 해주면 중복된 수들이 다 제거가 되는 것입니다. 

 

이는 erase를 통해 각각 없애줄 때보다 훨씬 간단하므로 익혀두셔야 알 수 있는 풀이입니다. 

 

그리고 제거해준 뒤 sort()를 통해 정렬을 해준 다음 bool을 하나 만들어주었습니다. 이는 뒤에 for문을 통해 true false를 판별할 때 사용합니다.

 

bool isgroup = true; 이런 식으로 for문 바깥에 정의를 해준 다음 만약 중복되는 수가 있다면 isgroup = false;로 만듭니다. 그리고 if(isgroup) count ++; 를 통해 isgroup이 true일때만 count 가 ++되도록 해줍니다. 

 

코드2

#include <iostream>
using namespace std;

int main() { 
	int N;                                // 입력받을 단어의 개수
	string word;                          // 입력받은 단어
	int count = 0;                        // 그룹 단어가 아니라면 카운트

	cin >> N;
	for (int i = 0; i < N; i++) {
		cin >> word;
        
		// 단어에서 알파벳 문자의 출현유무를 나타내는 배열 (출현없으면 false)
		bool alphabet[26] = { false, };        
		alphabet[(int)(word[0]) - 97] = true;  // 첫번째 단어값을 true로 설정

		for (int i = 1; i < word.size(); i++) {
        
			// 1. i번째 문자가 i-1번째 문자와 같으면 연속이므로 넘어간다.
			if (word[i] == word[i - 1]) {
				continue;
			}
            
			// 2. i번째 문자가 i-1번째 문자와 같지 않고, (연속하지 않고)
			//    해당 배열값이 true라면 (이미 나왔던 문자라면)
			else if(word[i] != word[i - 1] 
            		&& alphabet[(int)(word[i]) - 97] == true){
				count++;	// 그룹단어가 아니므로 카운트
				break;
			}
            
			// 3. 위의 두 경우에 해당하지 않는 경우
			//    처음 등장한 문자인 경우
			else {
				alphabet[(int)(word[i]) - 97] = true;
			}
		}
	}

	// 그룹 단어의 개수 = 전체단어의 개수 - 그룹단어가 아닌 단어의 개수
	cout << N - count;

	return 0;
}
출처: https://beginnerdeveloper-lit.tistory.com/104 [초보 개발자의 이야기, 릿허브:티스토리]

다른 블로그에서 쓴 풀이입니다. 

 

여기서는 저와 다르게 모든 단어의 수를 제거하지 않고 구하는 방식을 했습니다. bool alphabet[26] = {false, }; 이것을 통해 만약 알파벳이 출현이 없으면 false가 나오게끔 해주었습니다. alphabet[(int)(word[0]) - 97] = true;를 통해 첫번째 단어의 경우 true를 해주었습니다. 

 

이후 for문을 통해서 i와 i-1이 같으면 연속이므로 넘기고 이후에 i 번째 문자와 i-1문자와 같지 않고 해당 배열값이 true라면 그룹단어가 아니므로 count++를 합니다. 나중에 전체 단어 - count를 통해 출력을 해줄 것입니다. 

 

그리고 만약 두 경우에 해당하지 않을 경우 처음 등장하는 문자의 경우 alphabet[(int)(word[i]) - 97] = true;를 통해 alphabet배열이 true로 바껴지게 만들어줍니다.

 

위의 alphabet 배열은 true와 false로 이루어진 bool 배열입니다. 제가 풀이한 두개의 코드 모두 bool 함수를 쓸 줄 알아야 해당 문제를 풀 수 있습니다. 그리고 word[i] - 97은 익혀두셔야합니다. a의 ASCII코드가 97이기 때문에 a 부터 순서대로 0 , 1, 2,  ... 26까지 나오게 되는 것입니다.