프로그래머스 입문 120853 컨트롤 제트
문제
숫자와 "Z"가 공백으로 구분된 문자열 s가 매개변수로 주어진다.
숫자가 나오면 합계에 더하고, "Z"가 나오면 합계에서 직전 숫자를 빼면 된다.
| s | result |
|---|---|
| “1 2 Z 3” | 4 |
| “10 20 30 40” | 100 |
| “10 Z 20 Z 1” | 1 |
| “10 Z 20 Z” | 0 |
| “-1 -2 -3 Z” | -3 |
풀이
직전 정수값 추적으로 취소 처리하기
#include <stdlib.h>
#include <string.h>
int solution(const char* s)
{
int prev_num;
int sum = 0;
char buffer[256];
strcpy(buffer, s);
char* token = strtok(buffer, " ");
while (token != NULL)
{
if (strcmp(token, "Z") == 0)
{
sum -= prev_num;
}
else
{
int num = atoi(token);
sum += num;
prev_num = num;
}
token = strtok(NULL, " ");
}
return sum;
}
strtok로 공백으로 구분된 토큰을 하나씩 가져온다.
strcmp는 문자열을 비교하는 함수이므로, Z가 한 글자여도 문자열 리터럴인 "Z"를 인자로 넘긴다.
토큰이 "Z"가 아니라면 정수로 변환한 뒤 sum에 더한다.
이때 이후 "Z"를 만났을 때 직전 덧셈을 취소할 수 있도록, 더한 값을 prev_num에 저장해 둔다.
토큰이 "Z"라면 sum에서 prev_num을 빼서 직전 덧셈을 취소한다.
취소 값을 배열에 저장해 합계 구하기
#include <stdlib.h>
#include <string.h>
int solution(const char* s)
{
int count = 0;
int nums[256];
int sum = 0;
char buffer[256];
strcpy(buffer, s);
char* token = strtok(buffer, " ");
while (token != NULL)
{
if (strcmp(token, "Z") == 0)
{
nums[count] = nums[count - 1] * -1;
}
else
{
nums[count] = atoi(token);
}
count++;
token = strtok(NULL, " ");
}
for (int i = 0; i < count; i++)
{
sum += nums[i];
}
return sum;
}
앞선 방식은 토큰 판별과 변환, 계산을 하나의 반복문에서 모두 처리했다.
이번 방식은 문자열을 int 배열로 바꾼 뒤 합계를 구한다.
숫자 토큰은 int 값으로 변환해 배열에 추가하고, "Z"를 만나면 배열에 저장된 직전 값의 부호를 바꾼 값을 새 원소로 추가한다.
이렇게 하면 "Z"가 직전 값을 빼야 한다는 의미를 배열 안에 기록할 수 있다.
배열이 완성되면 모든 값을 더해 최종 합계를 구한다.
strtok 없이 구현하기
#include <stdlib.h>
int get_token_length(const char* current)
{
int length = 0;
if (current[length] == '-')
{
length++;
}
while (current[length] >= '0' && current[length] <= '9')
{
length++;
}
return length;
}
int solution(const char* s)
{
int sum = 0;
int prev_num = 0;
const char* current = s;
while (*current != '\0')
{
if (*current == 'Z')
{
sum -= prev_num;
current++;
}
else
{
int num = atoi(current);
sum += num;
prev_num = num;
current += get_token_length(current);
}
if (*current == ' ')
{
current++;
}
}
return sum;
}
strtok를 사용할 수 없다면 atoi가 문자열 앞쪽의 유효한 정수 부분만 변환한다는 점을 이용할 수 있다.
예를 들어 atoi("-123abc")와 atoi("-123 abc")는 정수 -123을 반환한다.
따라서 현재 포인터 위치에서 atoi를 호출하면 별도로 토큰을 잘라내지 않아도 정수값을 얻을 수 있다.
이후 다음 토큰을 가리키도록 포인터를 이동시킨다.