오늘 CodeKata는 2문제를 풀었다. 두 번째 문제는 이전에 풀었던 문제였는데, 혹여나 지금의 나라면, 다른 방식으로 풀 수 있지 않을까라는 기대와 함께 여러 시도를 해봤지만, 보기 좋게 실패해서 결국 이전 코드를 Kotlin으로 옮기는 수준으로 그쳐버렸다.
이후 GIT에 대해 알아봤지만, 어느정도 아는 내용들이고, 그냥 글만 읽자니 갑자기 귀찮아지고, 내가 맡고 있는 파트를 기다리는 팀원이 계셔서 그냥 dev 브랜치에 Merge를 하였다. 다행히 Confilct가 없었고, 내 코드를 쓰시는 팀원께서 별 다른 말이 없는 걸 보면, 별다른 문제가 없는 모양이다.
이후로 팀원이 코드를 Push하셔서 간단하게 리뷰를 했는데, Service층에서 엔티티를 그냥 사용하셔서 DTO로 바꾸라고 조언을 하였다. 그 다음 시간이 있어서 난이도 있는 알고리즘 문제를 풀었다. 푼 사람이 많아서 약간 얕잡아봤는데, 섞는 것을 고려해본 적이 없는 Bruteforce와 Greedy를 둘 다 써야하는 문제여서 시간이 오래 걸렸다.
https://www.acmicpc.net/problem/1285
1285번: 동전 뒤집기
첫째 줄에 20이하의 자연수 N이 주어진다. 둘째 줄부터 N줄에 걸쳐 N개씩 동전들의 초기 상태가 주어진다. 각 줄에는 한 행에 놓인 N개의 동전의 상태가 왼쪽부터 차례대로 주어지는데, 앞면이 위
www.acmicpc.net
이 문제에서 행과 열을 뒤집어봐서 전부 Bruteforce하게 풀면 2^40 의 시간 복잡도를 지니게 되어서 다른 방식을 찾아야한다. 나도 처음에 Bruteforce하게 풀었다가 보기 좋게 "시간 초과"란 결과를 얻었고, Greedy하게 푼 방식은 "틀렸습니다"란 결과를 얻었다. 결국 힌트를 찾아본 결과 내가 풀었던 Bruteforce한 방식과 Greedy한 방식을 반반 섞은 방법이 있다는 것을 알게되었다.
자세히 설명을 하자면, 일단 행 혹은 열만 바꾼 경우를 Bruteforce를 사용해 전부 구한다. 그 다음 바꾸지 않은 열과 행을 둘러보아서 내가 해당 줄을 뒤집으면, 답에 근접해지는지를 계산해서 그렇다면 뒤집고 아니면 냅둔다. 란 방식이다. 어찌보면 콜롬버스의 달걀 같은 해결법이라서 다소 허무해졌다.
#include <iostream>
#include <algorithm>
using namespace std;
int N, ans = 0;
int v[21];
char C;
void solve(int idx)
{
if (idx == N)
{
int s = 0;
for (int j = 0; j < N; j++)
{
int n = 0;
for (int i = 0; i < N; i++)
if ((v[i] & (1 << j)))
++n;
if (N - n < n) n = N - n;
s += n;
}
ans = min(ans, s);
return;
}
v[idx] = ((1 << N) - 1) ^ v[idx];
solve(idx + 1);
v[idx] = ((1 << N) - 1) ^ v[idx];
solve(idx + 1);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> N;
for (int i = 0; i < N; i++)
{
int n = 0;
for (int j = 0; j < N; j++)
{
cin >> C;
if (C == 'T')
{
n |= (1 << j);
++ans;
}
}
v[i] = n;
}
solve(0);
cout << ans << '\n';
}
푼 이후, 앞으로도 여유가 생길 것 같아서 팀과 대화를 했고, 내가 Image를 추가하기로 하였다. 즉, 앨범 커버를 사진을 추가해서 album과 연관 관계를 만들 것이다. 일단 내가 이전에 개인 프로젝트에서 Java로 이미지를 넣은 적이 있어서 해당 코드를 바탕으로 Kotlin에서 이미지를 넣는 작업을 하였다. 그리고 이미지 생성, 삭제, 조회 등의 기능을 넣었고, 무사히 구현을 마쳤다.
package com.example.codingsonyeondan.domain.image.service
import com.example.codingsonyeondan.domain.image.dto.ImageDTO
import com.example.codingsonyeondan.domain.image.dto.UploadFileDTO
import com.example.codingsonyeondan.domain.image.dto.UploadResultDTO
import com.example.codingsonyeondan.domain.image.model.Image
import com.example.codingsonyeondan.domain.image.repository.ImageRepository
import com.example.codingsonyeondan.infra.exception.ModelNotFoundException
import com.example.codingsonyeondan.infra.exception.NoImageException
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.repository.findByIdOrNull
import org.springframework.http.MediaType
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import java.util.UUID
@Service
class ImageServiceImpl(
@Value("\${org.example.upload.path}")
val uploadPath: String,
private val imageRepository: ImageRepository
): ImageService {
fun checkUploadedFileIsValidAndGetImage(uploadFileDTO: UploadFileDTO): MultipartFile
{
val image = uploadFileDTO.multipartFile ?: throw NoImageException()
if(!image.contentType?.startsWith("image")!!) throw NoImageException()
return image
}
fun getValidatedImage(uuid: String): Image
{
return imageRepository.findByIdOrNull(uuid) ?: throw ModelNotFoundException("Image", uuid)
}
@Transactional
override fun uploadImage(uploadFileDTO: UploadFileDTO): UploadResultDTO {
val image = checkUploadedFileIsValidAndGetImage(uploadFileDTO)
var originalName = image.originalFilename!!
originalName = originalName.replace("_", "-")
val uuid = UUID.randomUUID().toString()
val savePath = Paths.get(uploadPath, uuid+"_"+originalName)
image.transferTo(savePath)
imageRepository.save(Image(uuid, originalName))
return UploadResultDTO(uuid, originalName)
}
override fun getImage(uuid: String): ImageDTO {
val image = getValidatedImage(uuid)
return ImageDTO.from(image)
}
@Transactional
override fun deleteImage(uuid: String)
{
val image = getValidatedImage(uuid)
imageRepository.delete(image)
File(Paths.get(uploadPath, image.getLink()).toUri()).delete()
}
}
내일은 앨범과 연관관계를 넣고 마무리를 지을 예정이다.
'부트캠프 일지' 카테고리의 다른 글
| 부트캠프 32일차 후기 (1) | 2024.01.11 |
|---|---|
| 부트캠프 31일차 후기 (1) | 2024.01.10 |
| 부트캠프 29일차 후기 (1) | 2024.01.08 |
| 부트캠프 28일차 후기 (1) | 2024.01.05 |
| 부트캠프 27일차 후기 (1) | 2024.01.04 |