C언어/BAEKJOON

[백준] 1764. 듣보잡

너굴맨이해치움 2022. 9. 18. 06:03

: 자료구조 - silver 4

 

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

 

1764번: 듣보잡

첫째 줄에 듣도 못한 사람의 수 N, 보도 못한 사람의 수 M이 주어진다. 이어서 둘째 줄부터 N개의 줄에 걸쳐 듣도 못한 사람의 이름과, N+2째 줄부터 보도 못한 사람의 이름이 순서대로 주어진다.

www.acmicpc.net

 

 

정답

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct list {
	char name[21];
};

struct list list1[1000000]; 
struct list list2[500000]; 

int compare(const void* a, const void* b) {
	return (strcmp((char*)a, (char*)b));
} 

int main() {
	int n, m, t;
	scanf("%d %d", &n, &m);
	t = n + m;

	for (int i = 0; i < t; i++) {
		gets(list1[i].name);
	}
	qsort(list1, t,
		sizeof(list1[0]), compare);

	int count = 0; 

	for (int i = 0; i < t; i++) {
		if (strcmp(list1[i].name, list1[i + 1].name) == 0) {
			strcpy(list2[count].name, list1[i].name);
			count++;
			i++; 
		}
	}

	printf("%d\n", count); 
	for (int i = 0; i < count; i++) {
		puts(list2[i].name);
	}
	
	return 0;
}

 


해설

1. 듣도 못한 사람과 보도 못한 사람의 이름을 100만 칸짜리 하나의 배열에 함께 담아 알파벳순으로 정렬한다.

2. 정렬 시 중복되는 문자열은 함께 붙게 되므로, 반복문을 통해 중복되는 문자열을 찾아내 별도의 리스트에 복사한다.

3. 복사한 중복 리스트를 출력한다.

(원래의 배열이 알파벳순으로 정렬되어 있었으므로 이 배열도 자연히 정렬된 순서대로 원소를 담게 될 것이다.)

 

 

1. stdio.h, string.h, stdlib.h 세 가지의 헤더파일을 다운받는다.

각각 표준 입출력, 문자열 복사와 비교, 정렬을 위한 qsort 내장함수를 사용하기 위함이다.

문자열은 정렬을 위해 구조체로 만들어 놓는다. 이 구조체로 배열을 두 개 선언한다.

100만 칸짜리 배열은 입력값을 담고 정렬하는 배열, 50만 칸짜리 배열은 중복되는 것을 담는 배열이다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct list {
	char name[21];
}; //명단 한 칸의 자료형 (최대 20자)
//char*형으로 선언하면 오류가 남

struct list list1[1000000]; //입력값을 담는 리스트
struct list list2[500000]; //중복되는 것을 담는 리스트

 

 

2. qsort 내장함수에 사용할 비교함수이다.

strcmp는 두 문자열이 같으면 0, 다르면 알파벳순으로 비교한 결과를 1 또는 -1로 반환하므로

이 함수의 리턴값을 이용해 알파벳순 정렬을 할 수 있다.

int compare(const void* a, const void* b) {
	return (strcmp((char*)a, (char*)b));
} //정렬을 위한 비교함수

 

3. 입력값으로 받을 두 목록의 원소갯수를 각각 받은 뒤 둘을 합하여 t에 따로 저장한다.

그리고 t만큼의 원소를 list1에 통합하여 받는다.

이후 qsort를 이용해 입력값을 사전순으로 정렬한다.

int main() {
	int n, m, t;
	scanf("%d %d", &n, &m);
	t = n + m;

	for (int i = 0; i < t; i++) {
		gets(list1[i].name);
	} //n개와 m개의 이름을 같은 리스트에 입력

	qsort(list1, t,
		sizeof(list1[0]), compare);
	//퀵 정렬 (정렬할 배열, 자료갯수, 자료크기, 비교함수)

 

4. 중복된 문자열을 복사할 리스트의 인덱스로 사용할 변수를 0으로 초기화시킨다.

그리고 반복문을 돌려 중복을 찾아낸다. i번째 이름과 i+1번째 이름이 같다면 해당 문자열을 list2로 복사하고,

list2 배열의 인덱스를 하나 증가, i도 하나 증가(다음 문자열은 검사할 필요 없으므로) 시키면 된다.

	int count = 0; //list2 배열의 인덱스

	for (int i = 0; i < t; i++) {
		if (strcmp(list1[i].name, list1[i + 1].name) == 0) {
			//정렬된 명단의 다음 이름이 현재 이름과 같다면
			strcpy(list2[count].name, list1[i].name);
			count++; //list2 배열은 다음 인덱스로 넘기기
			i++; //list1 배열의 다음 원소는 동일하므로 패스
		}
	}

 

 

5. 이후 count 변수로 센 중복 리스트의 원소 수와, 해당 리스트에 담긴 모든 원소를 출력하면 된다.

	printf("%d\n", count); //중복 리스트의 원소수
	for (int i = 0; i < count; i++) {
		puts(list2[i].name);
		//중복 리스트의 원소
	}
	
	return 0;
}