이 문제는 '문자'로 입력을 받은 후 그 문자의 '아스키 코드 값'을 출력하는 문제입니다. C언어 방식으로 접근하면 아주 간단합니다. char type의 변수를 선언한 후에 그 변수로 '문자'로 입력을 받은 후 출력을 할때는 정수형 출력을 하게 되면 입력 받은 문자를 그대로 출력을 하는 것이 아닌 아스키 코드의 값으로 출력을 하게 됩니다. 이번 문제도 아주 간단한 문제이기 때문에 flow chart와 key point는 생략하고 넘어가도록 하겠습니다.

 

아스키 코드 표

#include <iostream>

using namespace std;

int main(){
    char ch;

    scanf("%c", &ch);

    printf("%d\n", ch);

    return 0;
}

 

 

 

 

  배열 문제는 대부분 간단하게 풀리는 문제가 많은 것 같습니다. 아무래도 1차원 배열이다 보니 값을 활용해 문제를 내려다 보니 한계가 있는 것 같습니다. 문제로 돌아가서 5명의 시험 점수를 평균내서 출력하는 간단한 문제입니다. 하지만 여기서 조건이 하나 추가되는데 40점 미만인 학생은 보충학습을 통해 40점을 가져갈 수 있다는 것입니다. 그리고 보충학습은 선택이 아닌 필수이므로 40점 미만 학생은 전부 40점 처리해서 풀면 됩니다. 아주 간단하죠. 출력또한 정수형으로 출력하기 때문에 자료형을 신경써줄 필요가 없습니다.

이번 문제는 간단하게 풀리기 때문에 flow chart를 생략하고 코드와 출력 결과를 첨부하고 끝내도록 하겠습니다.

 

#include <iostream>

using namespace std;

int main(){
    int answer = 0;

    for(int i = 0;i < 5;i++){
        int temp;
        scanf("%d", &temp);
        if(temp < 40)
            answer += 40;           // 40점 이하는 보충학습을 통해 40점을 받게됨
        else
            answer += temp;         // 그 이외에는 본인 점수 입력
    }
    answer /= 5;            // 인원 수 만큼 나누기(평균)

    printf("%d\n", answer);

    return 0;

}

 

 

 

이번 문제는 다른 배열 문제보다 더 간단한 것 같습니다. 문제 자체가 1씩 감소하고 있는지 1씩 증가하고 있는지를 물어보는 것이 아닌 첫 번째 판단 조건을 주었습니다. 가장 앞자리에 오는 음계가 1인지 8인지를 먼저 판단한다면 대부분의 케이스가 먼저 걸러질 것이라 예상됩니다. 그러고 나서 1과 8인 경우에서 다음 음계가 순차적으로 왔는지 판단하고 만약 순차적이지 않다면 그 부분에서 탐색을 종료하고 "mixed"라고 출력을 하면 됩니다. 처음 문제를 접근했던 방식은 8개의 배열을 모두 탐색하면서 인접한 배열의 원소의 차를 더해가지고 판별하는 방식으로 접근했었습니다.

예를 들어 첫 번째 예제인 "1 2 3 4 5 6 7 8"일 경우 배열을 탐색하면서 1과 2의 차는 -1이고, 다음 원소 2와 3의 차는 -1이므로 더 해나가다 보면 인접 배열의 차의 합은 -7이게 됩니다. 반대로 "8 7 6 5 4 3 2 1"일 경우에는 7이 나올 것입니다. 그 외의 경우는 전부 "mixed"라고 판단하도록 했습니다. 이렇게 할 경우 현재 배열의 크기가 8이기 때문에 탐색하는데 얼마 안 걸리지만 배열의 크기가 커질 경우 모두 탐색을 해야 알 수 있다는 점이 단점이라 생각했습니다. 또한, 모든 케이스에서 순차적으로 증가 또는 감소할 때만 저 값이 나온다는 확신이 없었기 때문에 접근 방법을 다르게 생각해봤습니다. 물론 이 방식이 코드도 훨씬 짧고 가독성도 높긴 하지만, 탐색 중간에 mixed임을 알면서도 끝까지 탐색해야 한다는 치명적 단점이 있기 때문에 다른 방식을 선택했습니다. 위에서 먼저 설명한 최종 접근 방식을 정리하면 아래와 같습니다.


* Key point!

1. 주어진 배열의 첫번째 원소가 1인지 8인지 판단

2. 그 다음 배열부터 순차적으로 증가 or 감소하는지 판단


 위의 알고리즘 대로라면 처음 구상했던것 보다 훨씬 빠를 것이라 예상합니다. 물론 배열의 크기가 8로 매우 작아 큰 차이는 안보이겠지만 배열의 크기가 매우 커진다면 차이가 조금씩 발생할 것입니다. 그래도 첫 번째 접근했던 방식도 O(n)의 시간 복잡도를 가지기 때문에 눈에 띄게 느려지는 것은 아닙니다. 오늘의 풀이는 여기까지 하고 하단에 소스코드와 출력 결과 사진을 첨부하고 마치도록 하겠습니다.

#include <iostream>

using namespace std;

int main()
{
    int note[8];        // 음계를 저장할 변수

    for (int i = 0; i < 8; i++)
        scanf("%d", &note[i]);

    if(note[0] == 1){
        bool ascending = true;
        for(int i = 1;i < 8;i++){
            if(note[i] != i + 1){
                ascending = false;
                break;
            }
        }
        if(ascending)
            printf("ascending\n");
        else
            printf("mixed\n");
    }       // 첫음계가 1부터 시작할때 ascending인지 판별

    else if(note[0] == 8){
        bool descending = true;
        for(int i = 1;i < 8;i++){
            if(note[i] != 8 - i){
                descending = false;
                break;
            }
        }
        if(descending)
            printf("descending\n");
        else
            printf("mixed\n");
    }       // 첫음계가 8부터 시작할때 descending인지 판별

    else
        printf("mixed\n");      // 그 이외의 모든 경우
    

    return 0;
}

 

BOJ 8958

 

오늘 풀어볼 문제는 OX퀴즈의 채점표를 보고 최종 점수를 출력해내는 코드를 구현하면 되는 문제입니다. 여기서 특별한 점은 문제를 연속해서 맞출 경우 더해지는 점수가 높아진다는 점입니다. 처음 맞춘 경우 1점이 더해지고, 두번째 연속으로 맞출경우 2점, 세번 연속 맞출 경우에는 3점이 오르는 시스템입니다. 하지만 여기서 중간에 한번 틀릴 경우 초기화가 되어 다시 1점부터 시작하게 됩니다. 제가 처음에 접근했을때는 '이전의 값이 X인지 O인지를 비교해서 풀면 되나?' 생각을 했었지만 그렇게 접근하는 것보다 간단한 방법이 있었습니다. 우선 string type으로 채점표를 입력 받은 뒤에 첫번째 문자부터 탐색해 나갈 것입니다. 여기서 int형 score 변수 하나를 선언해주고 0으로 초기화 해줍시다. 이제 문자열을 하나씩 검사할텐데 여기서 만약에 'O'가 들어왔을때는 score값을 1 증가시켜줍니다. 만약 반대로 'X'가 들어왔을 경우에는 score를 다시 0으로 되돌려줍니다. 그리고 이렇게 판별이 끝난 후에는 score값만큼 정답에 더해주면 됩니다.

아주 간단하게 풀리는 것을 볼 수 있습니다. 이해를 돕기 위해서 하단에 표로 어떻게 알고리즘이 돌아가는지 그리고 플로우차트까지 함께 첨부해 드리겠습니다.

플로우 차트


Example) OOXXOXXOOO

현재 문자

score

answer

O

1

1 (= 0 + 1)

O

2

3 (= 1 + 2)

X

0

3 (= 3 + 0)

X

0

3 (= 3 + 0)

O

1

4 (= 3 + 1)

X

0

4 (= 4 + 0)

X

0

4 (= 4 + 0)

O

1

5 (= 4 + 1)

O

2

7 (= 5 + 2)

O

3

10 (= 7 + 3)


이러한 알고리즘 형태로 돌아가게 됩니다. 요번 문제는 아주 간단하게 풀렸는데, 마지막으로 소스코드와 실행 결과 첨부하고 마치도록 하겠습니다.

#include <iostream>
#include <string>

using namespace std;

int main(){
    int T;

    scanf("%d", &T);

    for(int i = 0;i < T;i++){
        string problem;
        int score = 0;      // 현재 누적된 점수를 저장하는 변수
        int answer = 0;

        cin >> problem;

        for(int j = 0;j < problem.size();j++){
            if(problem[j] == 'O')
                score++;       // 정답을 맞을때마다 누적 점수를 1점씩 증가시킨다
            else
                score = 0;      // 오답일 경우 누적 점수를 0점으로 초기화
            answer += score;    // 현재 누적 점수를 정답에 더해준다
        }

        printf("%d\n", answer);
    }

    return 0;
}

결과창
채점 결과

BOJ 2577

 

우선 이 문제 풀이를 시작하기에 앞서 사용한 함수 한개에 대해 설명해드리겠습니다. int type 변수를 string type으로 변환하는 함수입니다. string.h 헤더파일에 있으며, string.h를 참조를 해주어야 사용할 수 있습니다.

- to_string(int type) : 전달 매개 변수 안에 int type의 값을 넣게 되면 return값으로 string type이 나오게 됩니다. 이 방법 외에도 sprintf라는 함수를 사용하면 int형으로 변환할 수 있지만 sprintf의 경우 전달 매개 변수 값이 char type의 배열이어야 한다는 점입니다. string은 char 배열보다 사용이 간편한 장점이 있기 때문에 to_string함수를 사용했습니다. 이 방법 외에도 나눗셈과 나머지 연산을 활용하여 변환하는 알고리즘을 설계하는 방법도 있습니다.

이제 문제 풀이를 해봅시다. 가장 먼저 A와 B와 C라는 세 값을 입력받아 곱한 결과값을 받아옵니다. 이제 여기서부터 문제가 시작인데 물론 곱한 결과값인 int형을 가지고 풀이를 진행할 수 있지만, 문자열로 변환하여 풀어보는 것이 훨신 간단하여 그 방법으로 풀어보았습니다. 가장 먼저 곱한 결과값을 string type으로 변환해야하는데 위에서 설명한 함수를 활용하면 간단하게 한줄만에 변환을 할 수 있습니다. 그렇게 변환한 stirng 변수를 이용해 각 자리수의 숫자의 개수를 측정할 것입니다. 방법은 아주 간단합니다. 변환된 string 변수를 첫번째 자리부터 끝까지 탐색을 하면서 숫자를 측정하면 되는데 이 과정속에서 아스키 코드를 활용할 것입니다. 0~9까지의 숫자의 개수를 측정할 int type의 배열 num을 만든 뒤 for문을 이용해 곱한 결과값을 string으로 바꾼 문자열을 탐색할 것입니다.

첫번째 자리의 문자열을 탐색했을때 1~9사이의 문자가 나올 것입니다. 이것을 아스키코드 값만큼 빼주게 되면 int type으로 쉽게 변환할 수 있습니다. 그 값을 num의 index에 넣어주고 그 값에 1을 더해주면 됩니다.

가장 쉬운 예로 설명을 하자면, 만약 곱셈의 결과가 329라고 했을때 앞자리부터 탐색을 시작합니다. 가장 첫번째 오는 문자는 '3'일겁니다. 여기서 '0'의 아스키코드 값만큼 빼주게 되면, '3'의 아스키값은 51이고 '0'의 아스키값은 48입니다. 그렇기 때문에 51-48 = 3이 나오게 됩니다. 이렇게 int type의 값으로 바꾸어 num 배열의 index에 넣어주게 되면, num[3]++이 될 것입니다. 그럼 현재 num 배열은 생성 초기에 0으로 초기화를 해주었다는 가정하에 아래의 표와 같이 저장이 될 것입니다.

0

1

2

3

4

5

6

7

8

9

0

0

0

1

0

0

0

0

0

0

다음 과정을 진행하면 329에서 3까지 탐색했으니 2의 문자열을 처리할 것입니다. 위와 동일하게 '2'에서 '0'의 계산을 해주면, 아스키 값으로 봤을때, 50-48 = 2로 num[2]++의 과정을 거치게 될것입니다. 그럼 num에 저장된 값을 확인해보면 아래와 같을 것입니다.

0

1

2

3

4

5

6

7

8

9

0

0

1

1

0

0

0

0

0

0

이렇게 반복하다보면 최종적으로는 아래의 표와같이 나올것입니다.

0

1

2

3

4

5

6

7

8

9

0

0

0

1

0

0

0

0

0

1

그럼 이 결과값을 그대로 for문을 이용하여 한줄한줄 출력해주면 문제가 해결이 됩니다.


* Key point

1. 곱셈의 결과값을 string type으로 변환

2. 문자열을 탐색하면서 아스키 값만큼 빼주어 num 배열 index에 넣어줌

3. 해당 배열 값을 1만큼 증가시켜줌


#include <iostream>
#include <string>

using namespace std;

void solution(int sum) {
	string str;
	int num[10] = { 0, };       // 0 ~ 9까지 각 자리수의 개수를 기록하는 변수

	str = to_string(sum);       // int type의 변수를 string type으로 바꿔주는 변수

	for (int i = 0; i < str.length(); i++)
		num[str[i] - '0']++;    // 곱셈 결과 값을 맨 앞자리부터 탐색하면서 개수를 세는 과정
	
	for (int i = 0; i < 10; i++)
		printf("%d\n", num[i]);     // 결과 값 출력

}
int main() {
	int A, B, C;
	int sum;

	scanf("%d %d %d", &A, &B, &C);

	sum = A * B * C;

	solution(sum);
}

결과창
채점 결과

BOJ 문제번호 1152

이 문제를 풀때, 문자열을 다루는 것에 익숙하지 않아 코드 작성에 애를 먹었던 기억이 있습니다. 기본적으로 C언어나 C++을 공부하신 분들은 string클래스를 활용하시면 보다 편리하게 풀 수 있으실 겁니다. 일단 문장을 입력받아야 하기때문에 gets()함수를 이용해서 입력을 받았습니다. 그리고 문장에서 단어의 개수를 판단하는 기준은 보통 띄어쓰기를 기준으로 나누어져있기 때문에 그 기준을 이용하여 코드를 작성했습니다. 하지만 2번째 예제를 입력했을때 올바른 정답이 나오지 않았었는데, 2번째 예제를 자세히 보면 띄어쓰기로 시작을 하는 것을 볼 수 있습니다. 그 부분 때문에 단어 한개를 추가로 인식하는 오류가 발생해서 flag라는 변수를 추가했습니다.

flag함수를 활용해서 문장을 인식하는 방법은 제가 임베디드때 센서 활용을 할때 자주 쓰던 방법입니다. 운영체제 과목을 수강할 당시 Test And Set이라는 기법에서 응용한 것입니다. 즉 내가 원하는 상태일때를 알려주는 변수입니다. C++을 활용하기 때문에 bool type을 활용하여 내가 알고자 하는 상황을 감지할 수 있습니다. 쉽게말해서 이 문제의 경우 내가 지금 문장을 앞에서부터 한글자 한글자 읽어나가고 있을 때, 지금 읽고있는 글자가 알파벳인지 공백문자인지를 구별하기 위한 변수라고 생각하면 됩니다. 내가 지금 현재 읽고 있는 문자가 알파벳일 경우 flag는 true로 초기화 시켜주면, 코드 내에서 알파벳을 읽고 있을때 동작 특성을 정해줄 수 있습니다.

이렇게 flag함수를 넣어주게 되면 처음에 공백부터 시작하는 문자열이나 끝에 공백이 들어가는 문자열이 오더라도 정확하게 단어의 개수만 측정할 수 있도록 할 수 있습니다.


* Key Point

1. 문자열을 구분하려면 공백을 기준으로 구분한다.

2. 문자열 중 시작부분과 끝부분에 공백이 올때의 오류를 처리해야 한다.

3. 문자열에서 내가 읽고 있는 것이 알파벳인지 공백문자인지 구분해야 한다.


#include <iostream>
#include <stdio.h>

#define MAX 1000001     // 입력받을 수 있는 문자열의 최대 크기
using namespace std;

int main() {
	char str[MAX];      // 입력 받은 문자열을 저장하는 변수
	int index = 0;         // 배열을 탐색할 위치 변수
	int answer = 0;         // 단어의 개수
	bool flag = false;      // 띄어쓰기 구분을 위한 flag

	gets(str);      // 문자열을 입력

	while (str[index] != '\0') {
		if (str[index] != ' ')
			flag = true;        // 처음에 띄어쓰기로 시작한 부분때문에 문장이 시작한 것을 알기 위한 장치
		else if(str[index] == ' ' && flag ) {
			flag = false;
			answer++;
		}       // 띄어쓰기를 기준으로 단어의 개수를 세도록 설정
		index++;
	}
	if(flag)
		answer++;       // 띄어쓰기를 기준으로 했기 때문에 마지막 단어를 세기 위한 작업

	printf("%d\n", answer);

}

채점 결과

 

BOJ 문제번호 2448
예제 입,출력

문제를 읽어보면 알겠지만 3x2k의 수만큼 별을 찍어내려간다고 합니다. 3, 6, 12... 이런식으로 내려가게 됩니다. 처음에는 기본적인 별찍기 문제와 동일하게 생각해서 해당 좌측에 공백문자를 출력한 후 별을 찍는 방식의 for문을 생각했었는데 도저히 규칙을 생각해낼 수가 없었습니다. 그래서 생각해낸 방법이 바로 공백의 문자를 가지고 있는 문자열을 생성하고 그 위에 입력받은 N의 값만큼 별모양을 찍어내면 되는 것 입니다.

그러려면 일단 아래와 같은 별 한 세트를 찍는 함수를 만들었습니다. 좌측에 보이는 별을 한세트로 봤습니다. 왜냐하면 가장 작은 수가 3줄을 찍어내는 것이기 때문입니다.

이제 두번째로 직면한 문제는 정확한 위치에 별을 찍는것이 문제인데, 이것은 시작점의 좌표만 정해주면 규칙적으로 찍어내면 됩니다. 이를 구현하기 위해서는 재귀호출함수를 활용해야하는데, 재귀 함수를 모르시는 분이 있을 수도 있어서 간략하게 설명하고 넘어가겠습니다.

 

* 재귀 호출 함수(Recursive call)

함수 안에서 함수 자기 자신을 호출하는 방식을 재귀 호출(Recursive call)이라고 합니다. 재귀 호출은 일반적인 상황에서는 잘 사용하지 않지만 알고리즘을 구현할 때 매우 유용하게 쓰입니다. 보통 알고리즘에 따라서 반복문으로 구현한 코드보다 재귀호출로 구현한 코드가 좀 더 직관적이고 이해하기 쉬운 경우가 많습니다. 재귀 함수의 경우 하나의 함수가 끝나기 전에 본인 자신을 호출하기 때문에 스택(Stack)에 계속 함수를 호출하여 공간을 차지하게 됩니다. 그렇기 때문에 반드시 재귀 함수를 종료하는 시점을 만들어주는 구문이 필요합니다. 그렇지 않으면 제한된 메모리 용량을 초과해 스택 오버플로우(Stack overflow)현상이 발생하게 됩니다.

이 재귀 호출 함수를 활용하여 문제를 풀어보도록 하겠습니다. 가장 먼저 N이 늘어나는 규칙을 보면 2의 배수 씩 늘어나는 것을 볼 수 있습니다. 여기서 첫번째 3을 입력했을때 가장 위에 위치하는 별은 3번째에 찍히게 됩니다. 두번째 N인 6이 들어왔을 경우, 가장 최상단에 찍히는 별은 6번째 찍히게 됩니다. 그 다음줄에 찍히는 두개의 삼각형 별은 3번째와 8번째에 삼각형의 가장 위의 별이 찍히게 됩니다. 즉, 가장 위의 삼각형을 그리는 함수, 아래의 두개의 삼각형을 그리는 함수를 재귀 호출 함수를 활용하여 3개를 작성하면 됩니다. 여기서 종료 구문은 삼각형의 모양을 그리고 나서 함수를 종료하게 만들면 됩니다. 가장 작은 단위는 N이 3일때이므로 입력받은 N을 2씩 나눠가며 재귀 호출을 하면 됩니다. 삼각형이 추가되는 모형을 보면 N이 6일때는 3의 아래에 삼각형을 두개씩 추가하는 모습이고, 12일때는 6에 6을 아래에 두개 더 추가하는 모습입니다. 플로우 차트로 표현해보면 아래와 같은 모습이지 않을까 싶습니다. 재귀 호출 함수기때문에 직관적으로 표현하긴 어렵지만 대강 표현하게 된다면 저렇게 될 것입니다.

위의 플로우 차트만으로는 설명이 조금 부족하지만 이해를 돕기 위해서 첨부했습니다. 재귀 함수는 N의 값과 x좌표와 y좌표가 계속 업데이트 되면서 새로운 자기 자신 함수를 호출합니다.

재귀 호출 함수를 활용하여 풀이대로 진행을 하게 되면 문제가 원하는 결과 값을 얻을 수 있습니다. 마지막으로 코드와 실행 결과를 보고 포스팅을 마치도록 하겠습니다.

#include <iostream>
#include <memory.h>
char space[3072][6144];		// 별을 찍을 공간 생성 k값이 최대 10까지인 것을 고려하여 배열 크기 생성)

void star(int N, int x, int y) {
	if (N == 3) {
		space[y][x] = '*';
		space[y + 1][x - 1] = '*';
		space[y + 1][x + 1] = '*';
		space[y + 2][x - 2] = '*';
		space[y + 2][x - 1] = '*';
		space[y + 2][x] = '*';
		space[y + 2][x + 1] = '*';
		space[y + 2][x + 2] = '*';
		return;
	}		// 별 한세트를 찍는 구문
	
	star(N / 2, x, y);		// 벌의 윗부분을 찍는 재귀 호출
	star(N / 2,x - (N / 2), y + (N / 2));	// 별의 좌하단 삼각형을 찍는 재귀 호출
	star(N / 2, x + (N / 2), y + (N / 2));	// 별의 우하단 삼각형을 찍는 재귀 호출
}
int main() {
	int N;
	int i, j;

	scanf("%d", &N);

	memset(space, ' ', sizeof(space));		// for문보다 memset으로 배열을 초기화 해주면 시간을 단축 할 수 있다고 한다.

	star(N, N - 1, 0);		// 입력받은 N을 넣어 함수 실행

	for (i = 0; i < N; i++) {
		for (j = 0; j < N * 2; j++) {
			printf("%c", space[i][j]);
		}
		printf("\n");
	}			// 별이 그려진 배열 출력
}

채점 결과

BOJ 문제번호 1065

  우선 주어지는 자연수 N의 범위는 1보다 크거나 같고, 1000보다 작거나 같은 자연수 이다. 예를 들어 123이 주어졌을 때, 각 자리수가 1씩 증가하기 때문에 등차수열로 볼 수 있다. 이와 동일한 조건을 만족하는 숫자들을 카운팅하여 지정된 범위 내에 등차수열 조건을 만족하는 수가 몇개인지 알아보는 것이다.  

  첫번째로, 한자리 숫자와 두자리 숫자의 자연수의 경우 무조건 등차수열이다. 그 이유는 한자리 자연수의 경우 비교를 할 다음 자리 숫자가 없기 때문에, 무조건 등차수열로 본다. 즉, 기본적으로 1~9를 포함하는 범위의 경우 9개는 기본적으로 등차수열을 갖는다. 두자리 자연수의 경우도 마찬가지로 무조건 등차수열이다. 10의 자리 숫자와 1의 자리 숫자의 차이가 공차가 되는데, 그 다음 이어지는 숫자와의 차이를 비교해 볼 수 없기 때문에 등차수열로 본다. 즉 93의 경우 공차가 -6이게 되는데, 다음 비교할 숫자가 없기때문에 등차수열로 보는 것이다. 이렇게 되면 주어진 자연수가 100이상일 경우 1~99는 모두 등차 수열이다. 이제 세자리 수부터 등차수열인지 비교를 해보면 된다. 

  문제를 접근할때, 과거의 공차와 현재의 공차를 비교하기 위해서 2개의 변수를 사용하였다. 그리고 1의자리부터 하나씩 올라가며 각 자리수의 차이를 비교해보고, 각 자리수의 차이가 달라질 경우 비교를 종료하고 다음 숫자를 탐색한다. 여기서 나머지연산과 나눗셈 연산을 사용하였는데, 우선 나머지 연산을 활용하여 제일 끝자리 숫자를 저장하고, 10으로 나누게 되면 자릿수가 한자리씩 밀리게 된다. 이렇게 되면 1의 자리 숫자들을 빼서 인접한 다음 자리 숫자와 차이를 구하기 쉽기 때문이다. 이 과정이 반복될때 10으로 나누는 값이 10보다 작아질 경우 모든 자리수의 차이가 같기때문이므로 정답을 하나 카운트하고 다음 숫자를 또 반복한다. 



% 글을 작성하다 보니, for문을 탐색할때 불필요하게 1부터 99까지 검사를 하는것 같다. for문의 경우 100이 넘을때만 동작하게 하고 그 이전의 자연수는 입력받은 자연수 그대로 출력하면 더 효율적일 것 같다.

#include <iostream>

int main() {
	int N;		// 입력받을 자연수 N
	int answer = 0;							// 등차수열을 만족하는 자연수의 개수
	int temp = 0, n = 0;					// temp: 1의 자리 숫자를 제거하고 남은 수를 임시 저장하는 변수, n: 남아있는 수의 가장 끝자리 숫자
	int diff = 0, before_diff = 0;			// diff: 현재 끝자리 숫자와 인접한 숫자의 차이, before_diff: 이전의 끝자리 숫자와 인접한 숫자의 차이

	scanf_s("%d", &N);

	for (int i = 1; i <= N; i++) {
		if (i < 100) {
			answer++;
		}			// 1~99의 숫자는 모두 등차수열이다
		else {
			temp = i;		
			n = temp % 10;			// 1의 자리 숫자를 저장
			temp = temp / 10;		// 1의 자리를 빼내고 남은 숫자
			diff = (temp % 10) - n;	// 1의 자리 숫자와 그 다음 자리 숫자의 차를 저장
			before_diff = diff;		// 과거 공차로 추정되는 값으로 저장
			while (1) {
				n = temp % 10;
				temp = temp / 10;
				diff = (temp % 10) - n;
				if (before_diff != diff)		// 과거 공차로 추정되는 값과 현재 공차로 추정되는 값을 비교하여 다를 경우 반복문을 나감
					break;
				if (temp < 10) {				// 모든 자리 숫자의 차이가 같을 경우 남은 숫자가 1자리게 되는데 이 경우 해당 숫자는 등차수열이므로 answer을 1개 추가하고 반복문을 나감
					answer++;
					break;
				}
				before_diff = diff;				// 과거 공차로 추정되는 값을 현재 사용된 공차로 업데이트
			}
		}
	}

	printf("%d\n", answer);

}

 

+ Recent posts