문제
영어 대소문자와 공백으로 이루어진 문자열이 주어진다. 이 문자열에는 몇 개의 단어가 있을까? 이를 구하는 프로그램을 작성하시오. 단, 한 단어가 여러 번 등장하면 등장한 횟수만큼 모두 세어야 한다.
입력
첫 줄에 영어 대소문자와 공백으로 이루어진 문자열이 주어진다. 이 문자열의 길이는 1,000,000을 넘지 않는다. 단어는 공백 한 개로 구분되며, 공백이 연속해서 나오는 경우는 없다. 또한 문자열은 공백으로 시작하거나 끝날 수 있다.
출력
첫째 줄에 단어의 개수를 출력한다.
예제 입력 1
The Curious Case of Benjamin Button
예제 출력 1
6
예제 입력 2
The first character is a blank
예제 출력 2
6
예제 입력 3
The last character is a blank
예제 출력 3
6
#문제 풀이 방법
1. 문자열이 입력되고, 문자열에 속한 단어의 개수를 출력한다.(단어는 공백으로 구분되고 중복될 수 있다.)
2. 문자열을 공백에 따라 구분하고, 개수를 파악하여 출력한다. 앞의 공백과 뒤의 공백, 개행문자는 제외시킨다.
→C/C++의 경우에는 strtok
함수를 이용하여 개수를 파악한다.(추가적인 방법도 있다.)
→Python의 경우에는 split()
함수를 이용하여 개수를 파악한다.
#C/C++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[1000000];
scanf("%[^\n]",str);
int a=0;
char *ptr=strtok(str," ");
while (ptr != NULL) //ptr이 NULL일때까지 (= strtok 함수가 NULL을 반환할때까지)
{
ptr = strtok(NULL, " "); //자른 문자 다음부터 구분자 또 찾기
a++;
}
printf("%d\n",a);
return 0;
}
cf.
C의 경우에는 공백이 포함된 문자열을 입력받기 위해서는 주의해야하는데
gets함수의 경우 백준에서 사용할 수 없다.
나도 처음에 gets
를 사용했다가 컴파일 에러가 뜨길래 당황했는데 찾아보니
"gets는 C에서 오래 전부터 deprecated 였으며, C++에서는 removed된지 오래입니다." 라고 한다.
(https://www.acmicpc.net/board/view/63336)
cf.
fgets
를 이용해서 풀어보려고 해봤는데 계속해서 틀렸다고 나왔다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[1000001];
fgets(str, sizeof(str), stdin);
int a=0;
char *ptr=strtok(str," ");
while (ptr != NULL) //ptr이 NULL일때까지 (= strtok 함수가 NULL을 반환할때까지)
{
ptr = strtok(NULL, " "); //자른 문자 다음부터 구분자 또 찾기
a++;
}
printf("%d\n",a);
return 0;
}
c언어의 입력 함수들을 살펴보면
scanf
함수는 공백문자(or 개행문자) 전까지 읽어드리고 마지막에 \0을 붙인다.gets
는 개행문자까지 읽어드리고, 개행문자를 \0으로 바꾼다.fgets
는 개행문자까지 읽어드리고, 그 뒤에 \0을 붙인다.
따라서 '\n'가 단어로 추가될 수 있기 때문에 다음과 같이 개행문자를 널문자로 바꿔주는 작업을 해야한다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[1000001];
fgets(str, sizeof(str), stdin);
str[strlen(str)-1]='\0';
int a=0;
char *ptr=strtok(str," ");
while (ptr != NULL) //ptr이 NULL일때까지 (= strtok 함수가 NULL을 반환할때까지)
{
ptr = strtok(NULL, " "); //자른 문자 다음부터 구분자 또 찾기
a++;
}
printf("%d",a);
return 0;
}
cf.
C++의 경우에는 Java나 Python처럼 간편하게 split()
을 이용하여 풀 수가 없고
위와 같이 string헤더파일에 있는 strtok
을 이용해야 한다.
추가적으로 다른 방법이 있나 살펴보았는데 getline
함수를 사용할 수 있었다.
1.cin.getline()
함수(istream 클래스의 멤버함수로서의 getline : std::istream::getline
)
(https://cplusplus.com/reference/istream/istream/getline/)
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
int a=0;
char str[1000002];//문자열의 길이가 100만이고 개행문자가 포함가능, 널문자까지 포함되므로 1000002이어야 한다!
while(cin.getline(str,sizeof(str),' '))
{
if(strcmp(str,"")==0||strcmp(str,"\n")==0)
{
continue;
}
a++;
}
cout<<a;
return 0;
}
2.getline
함수 (std namespace의 일반함수:std::getline
)
(https://cplusplus.com/reference/string/string/getline/?kw=getline)
istream& getline (istream& is, string& str, char delim);
//Extracts characters from is and stores them into str
//until the delimitation character delim is found
2번의 경우, 보다시피 매개변수로 istream객체를 받는다.
cin은 istream클래스의 객체이므로 이것을 사용할 수 있을 것이다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
int a=0;
string s;
while(getline(cin,s,' '))
{
if(s.size()==0||s.compare("\n")==0)
{
continue;
}
a++;
}
cout<<a;
return 0;
}
cf.
생각해보니 C++의 cin
을 쓰면 훨씬 더 간결하게 표현이 가능했다......
cin은 공백과 개행을 무시한다.(개행의 경우 버퍼에 남겨둔다.)
따라서 다음과 같이 쓸 수 있다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
int a=0;
string s;
while(cin>>s)
{
a++;
}
cout<<a;
return 0;
}
#Python
S=input()
print(len(S.split()))
'PS > 백준' 카테고리의 다른 글
[백준/Baekjoon]<3052번> 나머지 [C/C++/Python][Class 1] (2) | 2022.09.13 |
---|---|
[백준/Baekjoon]<2920번> 음계 [C/C++/Python][Class 1] (0) | 2022.09.12 |
[백준/Baekjoon]<2908번> 상수 [C/C++/Python][Class 1] (0) | 2022.08.03 |
[백준/Baekjoon]<2675번> 문자열 반복 [C/C++/Python][Class 1] (0) | 2022.08.02 |
[백준/Baekjoon]<2577번> 숫자의 개수 [C/C++/Python][Class 1] (0) | 2022.08.01 |