문제 설명

Leo는 카펫을 사러 갔다가 아래 그림과 같이 중앙에는 노란색으로 칠해져 있고 테두리 1줄은 갈색으로 칠해져 있는 격자 모양 카펫을 봤습니다.

Leo는 집으로 돌아와서 아까 본 카펫의 노란색과 갈색으로 색칠된 격자의 개수는 기억했지만, 전체 카펫의 크기는 기억하지 못했습니다.

Leo가 본 카펫에서 갈색 격자의 수 brown, 노란색 격자의 수 yellow가 매개변수로 주어질 때 카펫의 가로, 세로 크기를 순서대로 배열에 담아 return 하도록 solution 함수를 작성해주세요.

제한사항

  • 갈색 격자의 수 brown은 8 이상 5,000 이하인 자연수입니다.
  • 노란색 격자의 수 yellow는 1 이상 2,000,000 이하인 자연수입니다.
  • 카펫의 가로 길이는 세로 길이와 같거나, 세로 길이보다 깁니다.

문제 풀이

import math

def solution(brown, yellow):
    answer = []
    
    # 모든 타일의 수 = 넓이
    tiles = brown + yellow
    temp = []
    # 모든 가로, 세로 값의 경우의 수를 구함
    for i in range(3, int(math.sqrt(tiles)) + 1):
        if tiles % i == 0:
            if i > tiles / i:
                temp.append([i, int(tiles / i)])
            else:
                temp.append([int(tiles / i), i])
    # 정답의 타일과 일치할 때를 찾아냄
    for w, h in temp:
        if w * 2 + (h - 2) * 2 == brown:
            answer = [w, h]
            break
    
    return answer

여기서 모든 타일의 수는 카펫의 넓이와 같다. 카펫은 직사각형이기 때문에 가로 x 세로로 넓이가 결정된다. 갈색 타일의 경우 테두리를 둘러 싸고 있는데 타일의 수가 (가로) * 2 + (세로 - 1) * 2이다. 따라서 이 풀이에서는

1. 리스트 temp에 총 가능한 (가로 길이, 세로 길이) 쌍을 집어넣는다. (나머지 연산을 통해 나머지가 0이 나올 경우, 큰 쪽을 가로, 작은 쪽을 세로로 만들어 집어넣어주었다.)

2. temp에 들어있는 것 중 brown(갈색 타일의 수)와 (가로) * 2 + (세로 - 1) * 2를 비교해 같은 것을 반환한다.

라는 방법으로 풀었다.

문제 링크

programmers.co.kr/learn/courses/30/lessons/42842

'프로그래밍 언어 > python' 카테고리의 다른 글

Python(1) - 파일  (0) 2021.02.03
파이썬을 배워야 하는 이유  (0) 2021.01.10
import java.io.*;								// java.io패키지에 있는 클래스 모두를 import시킨다. 즉 이제 java.io패키지에 있는 클래스를 사용할 수 있다.
import java.util.Scanner;						// java.util패키지에 있는  Scanner클래스를 import시킨다. 즉 이제 Scanner클래스를 사용할 수 있다.

public class FileCopy {							// FileCopy클래스 시작
    public static void main(String[] args) {	// 메인 메소드 시작
        Scanner scanner = new Scanner(System.in);// 키보드로부터 입력 받는 바이너리 값을 문자열, 실수등으로 바꿔서 응용프로그램에 넣어주기위해서 scanner 객체 생성
        System.out.println("복사를 원하는 파일의 전체 경로를 입력하세요:");//복사를 원하는 파일의 전체 경로를 입력하세요: 를 콘솔창에 출력
        String scrFileName = scanner.nextLine();// 원본 파일이름을 키보드로부터 읽어와서 scrFileName에 저장한다.
        
        if (scrFileName.contains(".jpg")){		//입력 받은 파일명에서 확장자 검사하며, jpg파일이면 바디 실행
            FileInputStream fileInputStream = null;// 파일 입력 스트림 객체를 null로 초기화
            FileOutputStream fileOutputStream = null;// 파일 출력 스트림 객체를 null로 초기화

            try {								// 예외처리를 위해서 try - catch구문을 사용한다. => 여기서는 파일 읽기,쓰기, 닫기등을 하는 동안 예외가 발생할 수 있기 때문에 사용했다.
                File destFile = new File("C:\\Temp\\img_copy.jpg");// 파일 객체를 생성하면서 파일 경로를 C:\\Temp\\img_copy.jpg로 설정해주었다. 이는 복사본 파일에 해당한다.

                System.out.println("이미지파일을 복사합니다.");// 이미지파일을 복사합니다 를 콘솔창에 출력
                // File & FileInputStream & FileOutputStream 클래스이용 이미지 복사 코딩
                fileInputStream = new FileInputStream(scrFileName);// 파일 입력 스트림 객체를 생성 scrFileName은 원본파일 경로(이름)이다
                fileOutputStream = new FileOutputStream(destFile); // 파일 출력 스트림 객체를 생성 destFileName은 복사본파일 경로(이름)이다
                int c;							// c는 char를 의미하며 문자이다. 숫자로 표현
               while ((c = fileInputStream.read()) != -1)// 파일 끝을 만날때까지 반복하는 반복문이다.
                {								// 반복문 시작
                    fileOutputStream.write(c);	// 복사본 파일에 .jpg 복사
                }								// 반복문 끝
                fileInputStream.close();		//파일 입력 스트림 객체 닫기
                fileOutputStream.close();		//파일 출력 스트림 객체 닫기

            }catch (IOException e){				//예외를 catch하는 코드이다.IOException은 예외타입(예외클래스)이다.
                System.out.println("입출력 오류가 발생했습니다.");// 예외를 어떻게 처리할 것인지 작성하는 부분이다. 콘솔에 파일 입출력 오류 라고 출력하도록 했다.

            }									// catch문의 바디 종료
        }										// if문 바디 종료
        else if (scrFileName.contains(".txt")){//입력 받은 파일명에서 확장자 검사하며, txt파일이면 바디 실행

            FileReader filereader = null;		// Filereader객체를 null로 초기화
            FileWriter filewriter = null;		// Filewriter객체를 null로 초기화

            try {								// 예외처리를 위해서 try - catch구문을 사용한다. => 여기서는 파일 읽기,쓰기, 닫기등을 하는 동안 예외가 발생할 수 있기 때문에 사용했다.
                File destFile = new File("C:\\Temp\\txt_copy.txt");// 파일 객체를 생성하면서 파일 경로를 C:\\Temp\\img_copy.txt로 설정해주었다. 이는 복사본 파일에 해당한다.

                System.out.println("텍스트파일을 복사합니다.");//텍스트파일을 복사합니다. 를 콘솔창에 출력
                // File & FileReader & FileWriter 클래스 이용 텍스트 파일 복사 코딩
                filereader = new FileReader(scrFileName);// Filereader객체를 생성 scrFileName은 원본파일 경로(이름)이다
                filewriter = new FileWriter(destFile);// Filewriter객체를 생성 destFileName은 복사본파일 경로(이름)이다

                int c;									// c는 char를 의미하며 문자이다. 숫자로 표현
                while ((c = filereader.read()) != -1)// 파일 끝을 만날때까지 반복하는 반복문이다.
                {									// 반복문 시작
                    filewriter.write(c);			// 복사본 파일에 .txt 복사
                }									// 반복문 끝
                filereader.close();					// Filereader객체 닫기
                filewriter.close();					// Filewriter객체 닫기
            }catch (IOException e){					// 예외를 catch하는 코드이다.IOException은 예외타입(예외클래스)이다.
                System.out.println("입출력 오류가 발생했습니다.");// 예외를 어떻게 처리할 것인지 작성하는 부분이다. 콘솔에 파일 입출력 오류 라고 출력하도록 했다.

            }										// catch문의 바디 종료
        }											// else if문 바디 종료
        else										// 위의 조건 모두 만족하지않을때 
            System.out.println("처리할 수 없는 파일 형태입니다.");// 처리할 수 없는 파일 형태입니다. 를 콘솔창에 출력
    }												// 메인메소드 종료
}													// FileCopy클래스 종료

원래 일정대로라면 java계산기(2)블로그를 올렸어야하는데 문제해결이 아직덜되어 틈틈히 복습한 파일처리 개념 적용을 해봤습니다.

구조체, 공용체, 열거형을 공부하다보니 구조체를 가장 많이 쓸 것 같다는 생각이 들었다.

실제로 교수님도 그런 얘기를 하신 기억이 어렴풋이 나는 것 같기도..?

 

우선은 하나씩 틀 잡아놨던, 구조체를 사용하지 않은 초기수준 코드다.

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

int main(void)
{
	int a, b, c, d, n, A, B;
	double C, D;

	printf("첫번째 복소수의 실수부와 허수부를 입력하시오: ");
	scanf("%d %d", &a, &b);
	printf("첫번째 복소수의 실수부와 허수부를 입력하시오: ");
	scanf("%d %d", &c, &d);

	printf("\n원하는 연산번호를 입력하시오(1.덧셈, 2.뺄셈, 3.곱셈, 4.절대값):");
	scanf("%d", &n);

	if (n == 1)
	{
		A = a + c;
		B = b + d;
		printf("입력한 연산번호: 1.덧셈\n\n");
		printf("\n연산결과: %d+%di", A, B);
	}
	else if (n == 2)
	{
		A = a - c;
		B = b - d;
		printf("입력한 연산번호: 2.뺄셈\n\n");
		if (B > 0)
			printf("\n연산결과: %d+%di", A, B);
		else
			printf("\n연산결과: %d%di", A, B);
	}
	else if (n == 3)
	{
		A = ((a * c) - (b * d));
		B = ((a * d) + (b * c));
		printf("입력한 연산번호: 3.곱셈\n\n");
		printf("\n연산결과: %d+%di", A, B);
	}
	else
	{
		C = sqrt(a * a + b * b);
		D = sqrt(c * c + d * d);
		printf("입력한 연산번호: 4.절대값\n\n");
		printf("\n연산결과: %.2f, %.2f", C, D);
	}


	return 0;
}

 

그래서 구조체를 최대한 활용해서 코드를 다시 작성해보았다.

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

struct complex {
	double real;
	double imagin;
};

struct complex add(struct complex x, struct complex y);
struct complex sub(struct complex x, struct complex y);
struct complex mul(struct complex x, struct complex y);
struct complex sqrts(struct complex x);

int main(void)
{
	struct complex a, b, result, A, B;
	int n;
	

	printf("첫번째 복소수의 실수부와 허수부를 입력하시오: ");
	scanf("%lf %lf", &a.real, &a.imagin);
	printf("첫번째 복소수의 실수부와 허수부를 입력하시오: ");
	scanf("%lf %lf", &b.real, &b.imagin);

	printf("\n원하는 연산번호를 입력하시오(1.덧셈, 2.뺄셈, 3.곱셈, 4.절대값):");
	scanf("%d", &n);

	if (n == 1)
	{
		result = add(a,b);
		printf("입력한 연산번호: 1.덧셈\n\n");
		printf("\n연산결과: %lf+%lfi", result.real, result.imagin);
	}
	else if (n == 2)
	{
		result = sub(a,b);
		printf("입력한 연산번호: 2.뺄셈\n\n");
		if (result.imagin > 0)
			printf("\n연산결과: %lf+%lfi", result.real, result.imagin);
		else
			printf("\n연산결과: %lf%lfi", result.real, result.imagin);
	}
	else if (n == 3)
	{
		result = mul(a, b);
		printf("입력한 연산번호: 3.곱셈\n\n");
		if (result.imagin > 0)
			printf("\n연산결과: %lf+%lfi", result.real, result.imagin);
		else
			printf("\n연산결과: %lf%lfi", result.real, result.imagin);
	}
	else
	{
		A = sqrts(a);
		B = sqrts(b);
		printf("입력한 연산번호: 4.절대값\n\n");
		printf("\n연산결과: %.2lf, %.2lf", A.real, B.real);
	}

	return 0;
}

struct complex add(struct complex x, struct complex y)
{
	struct complex result;
	result.real = x.real + y.real;
	result.imagin = x.imagin + y.imagin;
	return result;
}

struct complex sub(struct complex x, struct complex y)
{
	struct complex result;
	result.real = x.real - y.real;
	result.imagin = x.imagin - y.imagin;
	return result;
}

struct complex mul(struct complex x, struct complex y)
{
	struct complex result;
	result.real = x.real * y.real - x.imagin * y.imagin;
	result.imagin = x.real * y.imagin + x.imagin * y.real;
	return result;
}

struct complex sqrts(struct complex x)
{
	struct complex result;
	result.real = sqrt(x.real * x.real + x.imagin * x.imagin);

	return result;
}

복소수의 절댓값을 계산할 때 두개의 복소수를 따로 계산하다보니 구조체 안에서 어떻게 나타내야할지 잘 몰랐는데 그냥 결과가 정수부분만 출력이 되는 것을 생각하고 result.real이라고 하니 결과가 나왔다.

구조체를 활용한 방법이 코드의 길이는 더 길었다. 그래도 더 복잡한 내용이 있을 때 유용할 것 같다. 구조체를 공부하며 가장 크게 느낀점은 구조체를 또 다른 구조체 안에 넣거나 할 때 머릿속으로 논리계산을 잘 해야겠다는 것이다. 그냥 코드를 짰을 때는 단순했는데 구조체를 써보니 복잡하다는 생각이 들었고 익숙해지도록 노력을 정말 많이 해야겠다는 생각이 들었다.

'프로그래밍 언어 > c' 카테고리의 다른 글

C언어 동적메모리  (0) 2021.01.20
C언어 구조체, 공용체, 열거형 (1)  (0) 2021.01.12
구조체와 공용체  (0) 2021.01.10
포인터와 함수 그리고 void형 포인터  (2) 2021.01.07
c언어 (1) - 포인터  (0) 2021.01.05

C언어 동적메모리

동적메모리할당이란 프로그램이 실행 도중에 동적으로 메모리를 할당받는 것이다.
필요한 만큼의 메모리를 시스템으로부터 할당받아서 사용하고, 사용이 끝나면 시스템에 메모리를  반납한다. 필요할 때 사용하고 반납하기 때문에 메모리를 매우 효율적으로 사용할 수 있다. 
동적 메모리는 malloc()계열의 라이브러리 함수를 사용하여 할당받을 수 있다. 프로그램이 수행되다가 malloc()함수를 만나면 운영체제가 호출되어서 필요한 만큼의 동적 메모리를 할당하게 된다.

 

1. 동적 메모리 할당


malloc()함수는 요청된 크기만큼의 메모리 공간을 찾아서 메모리의 주소를 반환한다.
단위는 바이트이다.(malloc(100)은 100바이트 공간을 요청하는 것)

요청한 메모리 공간을 할당할 수 없는 경우에는 NULL값 반환한다. 

여기서 반환하는 것은 void를 가리키는 포인터이다. 

void 포인터를 반환하는 것은 프로그래머가 메모리 공간을 어떤 자료형으로 사용할지 알 수 없기 때문이다. 

void 포인터는 다른 자료형의 포인터로 변경이 가능하다.  

따라서 프로그래머는 자신이 사용하고자 하는 자료형의 포인터로 형변환하여 사용해야 한다.

 

 

2. 동적 메모리 사용


동적 메모리 공간은 이름이 없어, 오직 포인터를 사용하여 사용할 수 있다. 

 

 

3. 동적 메모리 반납


free()는 동적으로 할당되었던 메모리 블록을 시스템에 반납한다. 

컴퓨터 시스템에서 동적으로 할당 가능한 메모리는 제한되어 있다. 따라서 할당받은 메모리의 사용이 끝났을 경우에는 반드시 메모리를 다른 프로그램이 사용할 수 있도록 반납하여야한다. 
(free()는 호출할 때는 할당된 메모리를 가리키는 포인터를 인수로 하여 호출하여야 한다.)

 

동적 메모리 할당의 가장 큰 장점은 사용자가 원하는 크기의 배열을 만들 수 있다는 점이라 사용자가 입력하는 크기의 배열을 만드는 예제를 실습해보았다. 

사용자에게 원하는  항목의 개수를 물어보고 그 크기의 배열을 동적으로 생성하여 배열에 사용자가 입력하는 데이터를 저장하고 다시 출력해보았다.

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

int main(void)
{
	int *p;
	int i, items;

	printf("항목의 개수는 몇개입니까? ");
	scanf("%d", &items);
	p = (int*)malloc(sizeof(int)*items);

	for (i = 0; i < items; i++) {
		printf("항목(정수)을 입력하시오: ");
		scanf("%d", &p[i]);
	}

	printf("\n입력된 값은 다음과 같습니다: \n");
	for (i = 0; i < items; i++)
		printf("%d ", p[i]);
	printf("\n");
	free(p);

	return 0;
}

+ Recent posts