[C] 백준 실버 3 달성 및 오답노트

김태희·2024년 5월 12일
0
post-custom-banner

백준 실버 3 달성


휴가 - 입원 - 휴가로 녹아버린 한달

휴가에서 복귀하자마자 교통사고가 나서 1주일간 입원했다.

퇴원을 하고 조금 있으니 또 휴가를 다녀오게 되었다.

그렇게 어제 밤에 부대로 복귀했는데, 다행히 입원 병동에서도 태블릿과 키보드 케이스로 코딩테스트와 토익을 공부했다.

지금 필요한 공부

목표한 바를 이루기 위해 전역전에 필요한 것은 오랜만에 정리해보자면 크게 3가지로 나뉜다.

  1. 900점 이상의 여유있는 토익 성적

  2. 자료구조에 대한 깊은 이해도와 이를 바탕으로 C/C++을 통해 구현할 수 있는 능력

  3. 이산수학, 미적분 전공과목에 대한 예습

이외에도 운동이나 영어회화, 사이드 프로젝트를 위한 프레임워크 학습 등도 욕심내고 있지만

위의 세 가지에 큰 비중을 두고 하루 하루를 보내고 있다.

토익은 이미 달성하였지만 좀더 욕심을 내서 950점까지 천천히 노려보면서에 백준 사이트를 통해 코딩테스트를 학습하고 있다.

C가 점점 익숙해짐에 따라 이전에 공부했던, 앞으로 공부할 여러 알고리즘과 자료구조를 직접 구현해보고 더 나아가 C++까지 익숙해질때까지 계속 백준을 풀것이다.

백준 골드 문제를 풀 경지에 달한다면 코딩테스트의 비중을 줄이고 다른 전공공부에 집중하는 시간을 보낼것이고, 사이드 프로젝트를 통해 갈고닦은 개발 능력을 사용하며 개발자의 길에 본격적으로 오르려고 한다.



토익 LC 485점 달성


900점을 달성하고 2주뒤 바로 본 시험에서 890점이 나왔다.

이번엔 컨디션도 안 좋았고, 시험장 앞에서 마라톤을 진행하여 듣기 시험 중간에 총을 쏘기도 하고 공사장 소리도 들려 집중력이 많이 부족했다.

마지막에 말려서 읽던걸 또 읽기도 했고 시간 배분을 잘했음에도 마지막 문제들을 다 날려 RC 점수가 30점이 내렸다.

하지만 다행히도 LC 점수가 20점이 올라 거의 만점에 가까운 점수를 맞았다.

문제는 집중력

이제 토익 기출문제를 풀어보면 몰라서 틀리는 것이 거의 없다.

시간을 재지않고 남는시간에 조금씩 문제를 풀면 200문제 중 1-2개만 틀릴때도 있으며, 오답노트를 작성하며 더 배워가는 공부는 이전만큼의 효율이 안나온다.

또한 익숙하지 않았던 호주나 영국 발음도 미리미리 대비하고 대화의 흐름을 예측하는 나만의 방법으로 잘 틀리지 않는다.

이제 950점까지 성적을 끌어올리기 위한 두 가지 방법은 실수를 줄이는것, 그리고 실전과 같은 분위기로 학습하여 2시간 동안 집중하는 능력을 기르는 것이라고 생각한다.

앞으론 쉬는날에는 전날 일찍자서 아침에 커피를 마시고 초콜릿을 먹으며 정해진 시간에 문제를 푸는 등 실전과 같은 환경을 최대한 조성하고 문제를 풀어 이를 극복하겠다.

[C] 코딩테스트 오답노트

문제를 풀며 어려웠던점이나 배운점들을 복습겸 정리하겠다.

2745 - 진법 변환

#include <stdio.h>
#include <string.h>
#include <math.h>

int main(void) {
    char a[10000];
    int n, result = 0;
    scanf("%s", a);
    scanf("%d", &n);
    int length = strlen(a);
    int count = length - 1;
    for (int i = 0; i < length; i++) {
        if (a[i] > '9') a[i] -= 7;
        result += (a[i] - '0') * pow(n, count--);
    }
    printf("%d", result);
    return 0;
}

아스키코드값 사용해서 char값 이용

n의 배열제곱으로 곱해서 더하기

반복문 안에 COUNT 선언하지말기 반복해서 재선언되서 결과 이상해짐


11005 - 진법 변환 2

#include <stdio.h>
#include <string.h>

int main(void) {
    int a, n, nam, count = 0;
    char b[10000];
    
    scanf("%d", &a);
    scanf("%d", &n);
    
    while(a>1){
      nam = a%n;
      a/=n;
      nam = nam>9 ? nam+'A'-10:nam+'0';
      b[count++] = nam;
    }
    
    b[count] = a + '0';
    
    if(b[strlen(b)-1] != '0') 
      printf("%c", b[strlen(b)-1]);
    
    for(int i = strlen(b)-2; i>=0; i--){
      printf("%c", b[i]);      
    }
}

10진법을 B진법으로 바꾸기

계속 나누면서 앞에서부터 나머지 뒤에서 넣고 반복 끝나면 몫 넣고
9보다 크면 알파벳으로 바꿔서 대입 후 역순으로 출력

nam+'A'-10 아스키 코드 이용 연습

배열 뒤에 0이면 예외처리를 통해 생략해야 빈 배열의 0값 출력 안됌

코드의 오류가 잘 안 보일때는 print문을 반복문이나 코드 중간에 넣어서

어디부터 값이 잘못되는지 확인하는 방법이 효율적임을 깨달음.


1193 - 분수찾기

#include <stdio.h>

int main(void) {
    int X;
    scanf("%d", &X); // 사용자로부터 X 값을 입력받음

    int n, d; // 분자와 분모를 저장할 변수 선언
    int sum = 0; // 분수의 순서를 계산할 변수 초기화
    int i = 1; // 분모를 나타낼 변수 초기화

    // X번째 분수를 찾기 위해 sum 변수를 이용하여 순서를 계산
    while (sum + i < X) {
        sum += i;
        i++;
    }

    // i가 홀수인 경우와 짝수인 경우를 나누어 처리
    if (i % 2 == 1) {
        n = i - (X - sum - 1); // 홀수 번째 분수일 때 분자 계산
        d = 1 + (X - sum - 1); // 홀수 번째 분수일 때 분모 계산
    } else {
        n = 1 + (X - sum - 1); // 짝수 번째 분수일 때 분자 계산
        d = i - (X - sum - 1); // 짝수 번째 분수일 때 분모 계산
    }

    // 결과 출력
    printf("%d/%d", n, d);

    return 0;
}

sum count 등의 값이 초기화되지 않아 앞에 나온값에 추가적으로 연산이 적용되어 오류가 생겼다. 반복문 내에서 재선언하는 등의 방법으로 초기화를 꼭 해주자.

또한 무작정 코드를 작성하려다 오랜 시간 동안 삽질한 문제이다.

수학 문제는 패턴을 제대로 파악하고 구현보다는 설계에 시간을 쏟는게 중요하다고 느꼈다.


1676 - 팩토리얼 0의개수

#include <stdio.h>

int main(void){
  int n, fac=1, count=0;

  scanf("%d", &n);

  while(n>1){
    fac*=n;
    n--;
  }

  while(fac%10==0){
    fac/=10;
    count++;
  }

  printf("%d", count);
}

처음에는 단순하게 팩토리얼을 구하고 뒷자리의 0을 세는 방식으로 문제를 해결하려 했다.

하지만 제출해보니 시간초과가 되어서 다른 방법을 찾아보았다.

뒷자리에 0이 나오려면 2와 5가 필요하다는 점을 알게되었다.

5에 비해 2는 훨씬 많은 빈도로 나오기에 2는 무시하고 5가 몇번 출연하는지를 세면 되는 문제였다.

5와 25, 125의 배수를 확인함으로써

예를 들어 25일때 5에서 한번 25에서 한번 총 두번 5를 세어주는 원리로 코드가 작동된다.

#include <stdio.h>

int main(void){
  int n, count=0;

  scanf("%d", &n);

  for(int i=1; i<=n; i++){
    if(i%5==0) count++;
    if(i%25==0) count++;
    if(i%125==0) count++;
  }

  printf("%d", count);
}



2231 - 분해합

내가 처음 짠 코드

#include <stdio.h>
#include <math.h>

int main(void) {
  int result, creator = -1;
  scanf("%d", &result);
  int count = 1, length = result;
  while (length > 10) {
    length /= 10;
    count++;
  }

  int i = result - 9 * count;
  while (1) {
    int sum = i;
    for (int j = 1; j <= count; j++) {
      sum += i % (int)pow(10, j) / (int)pow(10, j-1);
    }
    if (sum == result)
      creator = i;
    if(i > result)
      creator = 0;
    if (creator != -1)
      break;
    i++;
  }
  printf("%d", creator);
  return 0;
}

N의 가장 작은 생성자를 구하는 문제이다

하지만 내가 처음 짠 이 코드는 특정 문제로 잘 작동되지 않았는데 찾아보니 pow 함수 사용으로 인한 부동 소수점 정밀도 문제가 있었다.

이에 대한 설명을 chat gpt에게 요청해보았다.

부동 소수점 정밀도 문제는 컴퓨터에서 실수를 표현할 때 발생하는 문제 중 하나입니다.
컴퓨터는 부동 소수점 방식을 사용하여 실수를 표현하는데, 이 방식은 소수점의 위치를 나타내는 가수와 소수점의 위치를 나타내는 지수로 나뉩니다.

C언어의 pow 함수는 부동 소수점을 다루기 때문에, 정수 연산보다 부정확할 수 있습니다. 특히 pow(10, j)와 같이 사용될 때, 컴퓨터는 이를 부동 소수점 연산으로 처리하고 결과를 반환합니다. 이는 정확한 값을 얻을 수 없을 뿐만 아니라 성능에도 부담을 줄 수 있습니다.

예를 들어, pow(10, j)는 10의 j 제곱을 계산합니다. 그러나 컴퓨터는 내부적으로 이를 부동 소수점으로 처리하여 근사치를 반환합니다. 이 근사치는 때로는 예기치 않게 작은 오차를 가질 수 있습니다.

따라서 정수 계산을 수행할 때에는 가능한한 부동 소수점 연산을 피하고 정수 연산을 사용하는 것이 좋습니다. 위의 수정된 코드에서는 pow 함수 대신에 정수 연산을 사용하여 자릿수를 계산하고 있습니다. 이렇게 함으로써 정확성과 성능을 모두 향상시킬 수 있습니다.

쉽게말해 실수를 처리하는 pow 함수를 정수형으로 변환하여 사용하는 과정에서 컴퓨터 내부적인 작은 오차가 일어나 결과값에 차이가 생긴다는 말이다.

굳이 자릿수 구해서 pow 함수를 사용할 필요없이

while(temp>0) {
  sum += temp % 10;
  temp /= 10;
}

이런식으로 pow 함수 없이 문제를 해결할 수 있었다.

수정한 코드

#include <stdio.h>

int main(void) {
  int result, creator = -1;
  scanf("%d", &result);
  int count = 1, length = result;
  while (length > 10) {
    length /= 10;
    count++;
  }

  int i = result - 9 * count;
  while (1) {
    int sum = i;
    int temp = i;
    while(temp>0) {
      sum += temp % 10;
      temp /= 10;
    }
    if (sum == result)
      creator = i;
    if(i > result)
      creator = 0;
    if (creator != -1)
      break;
    i++;
  }
  printf("%d", creator);
  return 0;
}



2798 - 블랙잭

#include <stdio.h>

int main(void) {
  int a, b, card[100];
  scanf("%d %d", &a, &b);

  int i, j, k, max = 0, sum;

  for(int i=0; i<a; i++){
    scanf("%d", &card[i]);
  }

  for(i=0; i<a; i++){
    for(j=i+1; j<a; j++){
      for(k=j+1; k<a; k++){
        sum = card[i] + card[j] + card[k];
        if(sum<=b&&sum>max) max = sum;
      }
    }
  }
  printf("%d", max);
  return 0;
}

5개중 모든 경우의수 3개를 고르는 코드를 어떻게 구현할지 오랜시간 고민했다.

i j k

j=i+1 이런식으로 선택지를 하나씩 줄여가며 삼중 for문으로 해결할 수 있었다.


15829 - 해시

#include <stdio.h>

int main(void) {
  int a;
  long long sum=0, pow = 1;

  scanf("%d", &a);

  for(int i=0; i<a; i++){
    char c;
    scanf(" %c", &c);
    int element = c - 'a' + 1;
    sum += element * pow % 1234567891;
    sum %= 1234567891;
    pow *= 31;
    pow %= 1234567891;
  }

  printf("%lld", sum);

  return 0;
}

처음엔 쉬운 문제라고 생각했지만 메모리 부족 등으로 인해 고려할 점이 많았다.

텍스트 파일에서는 줄이 바뀔 때마다 개행 문자가 삽입되는데 scanf()와 같은 함수에서 개행 문자를 적절히 처리하지 않으면 의도치 않은 동작이 발생할 수 있다는점을 깨달았다.

개행문자땜에 결과값이 이상하게 나와 " %d"와 같이 한칸을 띄워서 해결할 수 있었다.

앞 문제에서 정수 연산에서 pow 안쓰는게 좋다고 배웠다.

제곱을 어떻게 표현할지 고민하다 pow값에 31을 반복문이 돌때마다 곱해주어 pow 함수 없이 제곱을 사용할 수 있었다.

다른 사람들이 작성한 코드를 찾아보며 1234567891과 같이 반복되는 쓸데없는 수는 앞으론 #define을 이용해서 가독성을 높여야겠다고 느꼈다.

분배법칙을 이용해 pow sum 값이 너무 커지지 않게 꾸준히 나눠줘서 불필요한 연산을 줄여 적은 메모리로 연산이 가능하도록 하는데에 신경썼고, long long int 형 자료형을 사용할 수 있었다.

아래 연산에서 a가 상대적으로 아주 작기에 나머지에 1234567891을 나눠주면서 줄이는게 가능했다.

(13 + 17) %10 = 13%10 + 17%10

1(a-매우작음)) * 10 % 7 = 1 * 3 똑같음



2869 - 달팽이

#include <stdio.h>

int main(void) {
  int a, b, c;
  scanf("%d %d %d", &a, &b, &c);

  int day = a-b; 

  int left = c-b;

  int last = left / day; 

  if(left - last * day>0) last++;

  printf("%d", last);

  return 0;
}

다른사람이 작성한 코드를 보니

(c-b-1) / (a-b) +1

이처럼 앞에다가 미리 1을 빼고 연산후 1을 더해

나머지를 굳이 구할필요없이 코드를 작성하는 사람도 있었다.

이런 발상이 인상깊어서 다음에 써먹으려고 기록한다.

이 문제에서도 시간제한이 있으니 count로 계산하는게 아니라 이젠 코드의 효율을 먼저 생각해보게 되었다.


1259 - 팰린드롬수

#include <stdio.h>
#include <string.h>

int main(void) { 
  char a[6];
while(1){  
    int flag = 1;

    scanf("%s", a);
    if(a[0]=='0') break;

    int b = strlen(a)-1;

    for(int i=0; i<b; i++){
      if(i>=b) break;
      if(a[i]!=a[b--]) flag = 0; 
    }

    if(flag == 1){
      printf("yes\n");
    }else{
      printf("no\n");
    }
}
  return 0;
}

메모리와 시간 제한도 있고 99999 이하의 정수로 범위가 제한되길래

정수말고 char *형으로 해결시 쉬울것이라 생각하고 문제를 풀기 시작하였다.

정수를 다루는 문제도 char * 형으로 풀 수 있다는 사실을 느낀 문제이다.


2609 - 최대공약수와 최소공배수

#include <stdio.h>

int gcd(int min, int max) {		
  int remainder = 1;
  while (remainder != 0) {
    remainder = max % min;
    max = min;
    min = remainder;
  }
  return max;
}

int lcm(int min, int max) {		
  return min * max / gcd(min, max);
}

int main() {

  int a, b, min, max;
  scanf("%d %d", &a, &b);
  if (a > b) {
    max = a;
    min = b;
  }
  else {
    max = b;
    min = a;
  }
  printf("%d\n%d", gcd(min, max), lcm(min, max));
}

저번에 재귀를 다루면서 gcd 즉 최대 공약수를 구했던 기억이 있는데 가물가물해 유클리드 호제법을 다시 찾아보고서야 문제를 풀 수 있었다.

다신 안 까먹게 적어야지..

유클리드 호제법 - 큰수에서 작은수를 나누면서 나머지 0될때까지 계속 나누면 나온다는 이론

그리고 추가적으로 아래의 공식도 새로 알게되었다.

두수의 곱 = 최대공약수 x 최소공배수

이 공식을 사용하니 쉽게 최소공배수를 구할 수 있었다.



2775 - 부녀회장이 될테야

#include <stdio.h>

int main(void){
  int a[15][14] = {0, }, t, n, k;
  scanf("%d", &t);

  for(int i=0; i<14; i++){ //i는 1호에서 14호까지 a[0][0] 은 0층 1호
    a[0][i] = i+1; 
  }

  for(int i=1; i<15; i++){
    for(int k=0; k<14; k++){
      for(int j=0; j<=k; j++){
        a[i][k] += a[i-1][j];
      }
    }
  }

  while(t--){
    scanf("%d", &k); //k층
    scanf("%d", &n); //n호

    printf("%d\n", a[k][n-1]); //k층 n호는 a[k][n-1]
  }
  return 0;
}
틀린 나의 일반화

n층 1호 => 2호 1명 => 1명 + (n+1) => 3호 1명 + (n+1) + (n+2).. 

2층 1명 4명 10명 20명..

1층 1명 3명 6명 10명...

0층 1호 2호 3호 4호 ...

처음엔 나름대로 위처럼 n층의 몇호를 바로 구하는 방법을 생각했으나 생각보다 복잡했고

2층까지만 분석하고 n층을 일반화 하려다보니 결국 결과값이 틀리게 출력되었고

알맞게 계산하려면 앞에 계산에 있던 저장할 공간을 확보하는 등 쉬운 문제를 풀려고 더 어려운걸 찾아야했다.

욕심을 버리고 범위를 15층으로 둔것을 보고 문제 제작자의 의도를 파악했다.

배열을 먼저 선언해 결과값을 비교하는것이 더욱 효율적이라는걸 깨달았다.

계산을 편하게 하려면 배열을 1개 더 길게 선언해서 1부터 사용하는게 편하다는 것도 깨달았고

배열을 초기화하는 습관도 들일 수 있는 문제였다.



10989 - 정렬 3

#include <stdio.h>

int main(void){
  int count[10001] = {0, }, n;

  scanf("%d", &n);

  for(int i=0; i<n; i++){
    int a;
    scanf("%d", &a);
    count[a]++;
  }

  for(int i=1; i<10001; i++){
    for(int j=0; j<count[i]; j++){
      printf("%d\n", i);
    }
  }

  return 0;
}

많은 정렬 알고리즘을 공부해보았지만 카운트 정렬이라는 것은 처음 보았다.

숫자에 한계가 있고 횟수가 많은데 메모리제한 있는 특정 경우에 정말 좋은 효율을 내는 정렬이었다.

(특정 수가 몇번나왔는지 세고 횟수만큼 출력하는 정렬)

추가적으로 다른 정렬문제를 풀다가 이전에 구현했던 버블 정렬을 다시한번 복습해볼 수 있었다.

for(int i=0; i<n-1; i++){
  for(int j=n-1; j>i; j--){
    if(a[j-1]>a[j]){
      두개 바꿔라;
    }
  }
}



11050 - 이항 계수 1

#include <stdio.h>

int main(void){
  int n, k, result;

  scanf("%d %d", &n, &k);

  int n_fac = 1, k_fac = 1, nk_fac = 1;

  for(int i = 2; i<=n; i++)
    n_fac *= i;

  for(int i = 2; i<=k; i++)
    k_fac *= i;

  for(int i = 2; i<=n-k; i++)
    nk_fac *= i;

  result = n_fac / (k_fac * nk_fac);

  printf("%d", result);

  return 0;
}

이전에 조합을 배우면서 사용했던 공식이 바로 이항계수였다.

주어진 크기의 순서없는 조합의 가짓수 - 이항계수

이항계수 무엇인지 어떻게 표현하는지를 알게되었다.



2751 - 수 정렬하기 2

자료구조와 알고리즘을 공부하다 코딩테스트로 넘어가기 직전 퀵 정렬을 구현하다 말았다.

이론을 다시한번 이해하고 C에서 qsort라는 내장함수를 사용해 정렬하는 방법을 익힐 수 있었다.

나중에 꼭 직접 재귀를 활용해 구현해보는 시간을 갖도록 하겠다.

<stdlib.h>에 내장되어 있음

qsort(배열주소, 배열 몇개인지, 배열 크기 각각의, compare마지막인자(함수 가르키는 포인터))
int compare(const void *a, const void *b){
   return strcmp( (char*)a, (char*)b );
}

int compare(const void *a, const void *b){
  if(*(int*)a > *(int*)b) 
    return 1;
  else if(*(int*)a < *(int*)b)
    return -1;  
  else
    return 0;
}

return 함수가 양수이면 자리를 바꾸는 점을 이용해 입맛에 맞게 compare 함수를 짜면 된다.

2024/5/29 수정 
return (*a-*b) 형태로 사용하는 사람들도 많지만 오버플로우 가능성이 존재해 좋지않은 방법이라고 한다.
그리고 const void * 형을 형변환하여 사용하거나 qsort 매개변수 내에서 int * 형으로 형변환을 시켜주는 방법을 둘다 이용할 수 있다.
#include <stdio.h>
#include <stdlib.h>

int compare(const void* a, const void* b) {
    if(*(int*)a > *(int*)b) 
    return 1;
  else if(*(int*)a < *(int*)b)
    return -1;  
  else
    return 0;
}

int main(void) {
    int n, a[1000000] = {0, };
    scanf("%d", &n);

    for(int i=0; i<n; i++){
        scanf("%d", &a[i]);
    }

    qsort(a, n, sizeof(a[0]), compare);

    for(int i=0; i<n; i++){
        printf("%d\n", a[i]);
    }

    return 0;
}



1181 - 단어 정렬

차이 string.h 헤더를 사용 strcmp를 compare 함수에 사용하며

compare 함수를 내 입맛대로 만들어볼 수 있었고 문자열을 정렬할 수 있었다.

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

int compare(const void* a, const void* b) {

    if(strlen(a) > strlen(b)) 
        return 1;

    if(strlen(a) < strlen(b)) 
        return -1;

    if(strlen(a) == strlen(b)) 
        return strcmp((char*)a, (char*)b);
}

int main(void) {
    char a[20000][51] = {0, };
    int n;
    
    scanf("%d", &n);
    
    for(int i=0; i<n; i++){
        scanf("%s", a[i]);
    }
    qsort(a, n, sizeof(a[0]), compare);
    
    for(int i=0; i<n; i++){
        if(strcmp(a[i], a[i+1])!=0) 
            printf("%s\n", a[i]);
    }
    
    return 0;
}

strcmp로 문자열을 비교하는 방법을 깨달았다.

Java에서도 함부로 문자열을 비교하다 오류가 발생한적이 많아 비교함수를 자주 썼었는데 C도 이제 이 실력까지 왔구나 싶다.

const void *
받아온 값을 확인만 하려 하는데 값이 너무 커서 포인터로 접근 했을때, 그 값이 바뀌는걸 어느정도 방지하고,동시에 바꾸지 않겠다는 의지를 쓸때 사용

strcmp((char*)a, (char*)b) 쓰려면 형변환 시켜줘야한다는 점도 잊지말자



10828 - 스택 구현

메모리할당과 구조체 없이 간단하게 배열만으로 스택을 구현해보았다.

이것도 더 어렵게 구현해봤었는데 백지상태에서 해보려니 어려웠다.

그치만 확실히 한번 정리하고 나니까 쉽게 배울 수 있었다.

배열하나에 top 하나만 있어도 간단하게 구현 가능했다.

#include <stdio.h>
#include <string.h>

int stack[10000];
int top = -1; //0~9999 연산 쉽게

int empty(){
    if(top==-1){
        return 1;
    }
    return 0;
}

int full(){
    if(top >= 9999){
        return 1;
    }return 0;
}

int check_top(){
    if(top != -1){
        return stack[top];
    }
    return -1;
}

void push(int data){
    if(!full()){
        top++;
        stack[top] = data;
    }        
}

int pop(){
    if(!empty()){
        return stack[top--];
    }
    return -1;
}

int size(){
    return top + 1;
}

int main(void) {
    int n;

    scanf("%d", &n);

    for(int i=0; i<n; i++){
        char a[10];
        int b;
        scanf("%s", a);
        if(strcmp(a, "push")==0){
            scanf("%d", &b);
            push(b);
        }else if(strcmp(a, "pop")==0){
            printf("%d\n", pop());
        }else if(strcmp(a, "size")==0){
            printf("%d\n", size());
        }else if(strcmp(a, "empty")==0){
            printf("%d\n", empty());
        }else if(strcmp(a, "top")==0){
            printf("%d\n", check_top());
        }
    }

    return 0;
}

!함수() 꼴은 return 값 0혹은 1일때만 사용해야한다 !!
-1일때 사용했다가 결과값 오류 발생



10845 - 큐

스택을 응용해 원형 큐를 구현해 문제를 쉽게 해결하였다.

확실히 이론을 아니까 금방 배우는것 같다.

프론트와 엔드 모두 10000넘어갈시에 다시 0으로 돌아와 효율적인 큐를 구현할 수 있었다.

#include <stdio.h>
#include <string.h>

int que[10000];
int front = 0; //0~9999 연산 쉽게
int end = 0;

int empty(){
    if(end-front==0){
        return 1;
    }
    return 0;
}

int full(){
    if(end-front == 9999 || end-front == -1){
        return 1;
    }return 0;
}

void push(int data){
    if(!full()){
        que[++end] = data;
    }else{
        if(end>=9999){
            end = 0;
        }else if(front>=9999){
            front = 0;
        }
        que[end] = data;
    }
}

int pop(){
    if(!empty()){
        return que[++front];
    }
    return -1;
}

int size(){
    return end-front;
}

int front_que(){
    if(!empty()){
        return que[front+1];
    }
    return -1;
}

int back_que(){
    if(!empty()){
        return que[end];
    }
    return -1;
}

int main(void) {
    int n;

    scanf("%d", &n);

    for(int i=0; i<n; i++){
        char a[10];
        int b;
        scanf("%s", a);
        if(strcmp(a, "push")==0){
            scanf("%d", &b);
            push(b);
        }else if(strcmp(a, "pop")==0){
            printf("%d\n", pop());
        }else if(strcmp(a, "size")==0){
            printf("%d\n", size());
        }else if(strcmp(a, "empty")==0){
            printf("%d\n", empty());
        }else if(strcmp(a, "front")==0){
            printf("%d\n", front_que());
        }else if(strcmp(a, "back")==0){
            printf("%d\n", back_que());
        }
    }

    return 0;
}



앞으로의 계획


내가 아무리 이론을 공부하고 알고리즘을 잘 구현해도 전체적인 실력이 아직 부족했다.

스택이나 정렬 알고리즘을 구현해봤어도 막상 관련된 문제를 직면하면 다시 학습을 해야했다.

하지만 백준의 클래스를 따라 난이도를 높여가며 점차 많은 문제를 풀다보니 처음엔 문제 해결에만 집중을 하고

그 다음엔 메모리를 신경쓰게되고 자연스레 실행 시간 즉 코드의 효율성까지 따지게 되는 발전이 있었다.

또 같은 자료구조를 다루더라도 여러 방법으로 응용하게 되니 더 깊이있는 학습이 될 뿐만 아니라 머리에도 잘 남는것 같았다.

그래서 자료구조를 책으로 공부하며 VELOG를 작성하던 기존의 틀에서 벗어나 당분간은 지금처럼 코딩테스트를 하며 느낀 회고록을 특정 티어나 수준에 도달할때마다 VELOG에 작성하면서 복습하는 글을 올릴것이다.

어느 정도 수준에 도달하면 기존에 하던 것처럼 한 가지를 깊게 파고드는 식의 포스트를 작성할 것이다.

부대에서 수능 공부를 하는 친구들 만큼 진정성있게 공부하여 후회없는 군생활을 보내고싶다.

post-custom-banner

0개의 댓글