PTA 배열과 정렬, 탐색 문제 풀이 및 핵심 알고리즘 설명

함수형 문제풀이

6-1 2차원 배열에서 최댓값과 그 위치 찾기

이 문제는 이중 반복문을 통해 2차원 배열 전체를 순회하며 최댓값과 해당 인덱스를 추적하는 기본적인 탐색 문제다. 전역 변수 RowCol에 최댓값의 위치를 저장해야 하며, 초기값 설정 시 주의가 필요하다.

int fun(int arr[4][M]) {
    int maxVal = arr[0][0];
    Row = 0; Col = 0;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < M; j++) {
            if (arr[i][j] > maxVal) {
                maxVal = arr[i][j];
                Row = i;
                Col = j;
            }
        }
    }
    return maxVal;
}

6-2 평균 계산 및 평균 이하 원소 개수 세기

전체 합을 구한 후 평균을 산출하고, 다시 한 번 순회하며 평균보다 작은 값의 개수를 카운팅한다. 실수형 연산과 출력 형식(%.2f)에 유의해야 한다.

int fun(float data[], int n) {
    float total = 0.0;
    for (int i = 0; i < n; i++) {
        total += data[i];
    }
    float avg = total / n;
    printf("ave=%.2f\n", avg);
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (data[i] < avg) count++;
    }
    return count;
}

6-3 파스칼 삼각형 생성

점화식 triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]을 활용하여 동적 계산을 수행한다. 양 끝 요소는 항상 1이며, 내부 요소는 위 두 요소의 합으로 채워진다.

void fun(int triangle[][N], int level) {
    for (int i = 0; i < level; i++) {
        triangle[i][0] = 1;
        triangle[i][i] = 1;
        for (int j = 1; j < i; j++) {
            triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
        }
    }
}

6-4 심사위원 점수 처리

배열 포인터를 사용하는 예제로, 최고점과 최저점을 제외한 나머지 점수의 평균을 계산한다. C 언어에서 배열 이름은 첫 번째 요소의 주소를 의미하므로, int *scoreint score[]는 함수 매개변수로 동일하게 작동한다.

double getScore(int *scores, int n) {
    int sum = 0, high = -1, low = 101;
    for (int i = 0; i < n; i++) {
        if (scores[i] > high) high = scores[i];
        if (scores[i] < low) low = scores[i];
        sum += scores[i];
    }
    sum -= (high + low);
    return (double)sum / (n - 2);
}

6-5 배열 정렬

기본적인 정렬 알고리즘을 구현하는 문제다. 아래는 버블 정렬과 퀵 정렬의 구현 예시이다.

버블 정렬:

void fun(int arr[], int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

퀵 정렬:

void quickSort(int nums[], int left, int right) {
    if (left >= right) return;
    int pivot = nums[(left + right) / 2];
    int i = left - 1, j = right + 1;
    while (i < j) {
        do i++; while (nums[i] < pivot);
        do j--; while (nums[j] > pivot);
        if (i < j) {
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
    }
    quickSort(nums, left, j);
    quickSort(nums, j + 1, right);
}

프로그래밍 문제

7-1 최댓값과 최소 인덱스 출력

입력 과정에서 바로 최댓값과 그 인덱스를 갱신하면 배열 저장 없이도 해결 가능하다.

#include <stdio.h>
int main() {
    int n, val, maxVal = -1, maxIdx = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &val);
        if (i == 0 || val > maxVal) {
            maxVal = val;
            maxIdx = i;
        }
    }
    printf("%d %d\n", maxVal, maxIdx);
    return 0;
}

7-2 문자열 역순 출력

공백을 포함한 한 줄 입력은 gets() 또는 fgets()로 처리하고, 문자 길이를 기준으로 뒤에서부터 출력한다.

#include <stdio.h>
#include <string.h>
int main() {
    char str[81];
    gets(str);
    int len = strlen(str);
    for (int i = len - 1; i >= 0; i--) {
        putchar(str[i]);
    }
    return 0;
}

7-3 행렬 각 행의 합 계산

m×n 행렬에서 각 행의 합을 즉시 출력함으로써 배열 저장을 생략할 수 있다.

int main() {
    int rows, cols;
    scanf("%d%d", &rows, &cols);
    for (int i = 0; i < rows; i++) {
        int rowSum = 0, num;
        for (int j = 0; j < cols; j++) {
            scanf("%d", &num);
            rowSum += num;
        }
        printf("%d\n", rowSum);
    }
    return 0;
}

7-4 최솟값과 최댓값 위치 교환

최솟값을 맨 앞으로 옮긴 후, 변경된 배열 상태에서 다시 최댓값의 위치를 탐색하여 마지막 위치와 교환해야 한다. 그렇지 않으면 인덱스 불일치 오류가 발생한다.

void swap(int *a, int *b) {
    int t = *a; *a = *b; *b = t;
}
int main() {
    int n, arr[100];
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", &arr[i]);

    int minIdx = 0;
    for (int i = 1; i < n; i++)
        if (arr[i] < arr[minIdx]) minIdx = i;
    swap(&arr[0], &arr[minIdx]);

    int maxIdx = 0;
    for (int i = 1; i < n; i++)
        if (arr[i] > arr[maxIdx]) maxIdx = i;
    swap(&arr[n-1], &arr[maxIdx]);

    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    return 0;
}

7-5 가장 많이 등장한 정수 찾기

해시 맵을 사용하지 않고 중첩 루프로 각 원소의 등장 횟수를 직접 계산한다. 시간 복잡도는 O(n²)지만, 입력 크기가 작아 문제가 되지 않는다.

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

    int bestCount = 0, bestNum = a[0];
    for (int i = 0; i < n; i++) {
        int cnt = 0;
        for (int j = 0; j < n; j++)
            if (a[j] == a[i]) cnt++;
        if (cnt > bestCount) {
            bestCount = cnt;
            bestNum = a[i];
        }
    }
    printf("%d %d\n", bestNum, bestCount);
    return 0;
}

7-6 알파벳 대소문자 변환

C 표준 라이브러리의 islower(), toupper() 등을 활용하여 조건별 변환을 수행한다. '#'은 종료 조건으로 간주하여 문자열을 종료시킨다.

#include <ctype.h>
int main() {
    char s[31];
    gets(s);
    for (int i = 0; s[i]; i++) {
        if (s[i] == '#') {
            s[i] = '\0';
            break;
        } else if (islower(s[i])) {
            s[i] = toupper(s[i]);
        } else if (isupper(s[i])) {
            s[i] = tolower(s[i]);
        }
    }
    puts(s);
    return 0;
}

7-7 특정 문자 등장 횟수 세기

문자(char)를 인덱스로 사용하는 정수 배열을 맵처럼 활용하여 빈도를 기록한다.

int main() {
    int freq[128] = {0};
    char text[81], target;
    gets(text);
    for (int i = 0; text[i]; i++) freq[text[i]]++;
    scanf(" %c", &target);
    printf("%d\n", freq[target]);
    return 0;
}

7-8 문장 내 단어 개수 세기

연속된 공백을 하나의 구분자로 취급하고, 앞뒤 공백은 무시해야 한다. 문자열 앞뒤에 더미 공백을 추가하여 일반화하는 방법도 효과적이다.

int main() {
    char line[10001];
    gets(line + 1);
    line[0] = ' ';
    int len = strlen(line);
    line[len] = ' ';
    line[len + 1] = '\0';

    int wordCount = 0;
    for (int i = 0; line[i]; i++) {
        if (line[i] == ' ') {
            while (line[i + 1] == ' ') i++;
            wordCount++;
        }
    }
    printf("%d\n", wordCount - 1);
    return 0;
}

7-9 주민등록번호 유효성 검사

가중치 배열과 검증 코드 매핑 테이블을 사전 정의하고, 각 자리의 가중합을 계산한 후 나머지를 기반으로 마지막 문자를 검증한다.

int weights[17] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
char verify[11] = {'1','0','X','9','8','7','6','5','4','3','2'};

int isValid(char id[]) {
    if (strlen(id) != 18) return 0;
    int sum = 0;
    for (int i = 0; i < 17; i++) {
        if (!isdigit(id[i])) return 0;
        sum += (id[i] - '0') * weights[i];
    }
    return id[17] == verify[sum % 11];
}

int main() {
    int n; scanf("%d", &n);
    char ids[100][20];
    for (int i = 0; i < n; i++) scanf("%s", ids[i]);

    int allValid = 1;
    for (int i = 0; i < n; i++) {
        if (!isValid(ids[i])) {
            printf("%s\n", ids[i]);
            allValid = 0;
        }
    }
    if (allValid) printf("All passed\n");
    return 0;
}

태그: C 배열 정렬 탐색 문자열

6월 28일 23:45에 게시됨