함수형 문제풀이
6-1 2차원 배열에서 최댓값과 그 위치 찾기
이 문제는 이중 반복문을 통해 2차원 배열 전체를 순회하며 최댓값과 해당 인덱스를 추적하는 기본적인 탐색 문제다. 전역 변수 Row와 Col에 최댓값의 위치를 저장해야 하며, 초기값 설정 시 주의가 필요하다.
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 *score와 int 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;
}