코트카타
33) 약수의 개수와 덧셈
나의 풀이
class Solution {
public int solution(int left, int right) {
int answer = 0;
int i = left;
while (i <= right) {
int count = 0;
int j = 1;
while (j <= i) {
if (i % j == 0) {
count++;
j++;
} else {
j++;
}
}
if (count % 2 == 0) {
answer += i;
} else {
answer -= i;
}
i++;
}
return answer;
}
}
Q1) left ~ right 계속 숫자가 ++되어야 함
-> int i = left; 변수로 선언하여 while문 안에서 i++하게 함
Q2) 약수 구하는 방법?
- 소인수 분해? -> 소수를 구하는 방법이 더 어려울 듯
- i % j == 0인 경우의 값을 배열이나 리스트에 넣어서 최종적으로 해당 배열이나 리스트의 length, size를 구할까?
-> 그러면 각 숫자에 해당하는 배열과 리스트를 계속 생성해야 함...
- count를 이용해서 count % 2 ==0인 경우에 더하고, 아닌 경우에는 빼자
=> 중첩 while문을 사용
1부터 자신의 수가 나올 때까지 반복해서 나누고 그 나머지가 0인 경우에만 count++ 했다.
다른 분들의 풀이
class Solution {
public int solution(int left, int right) {
int answer = 0;
for (int i=left;i<=right;i++) {
//제곱수인 경우 약수의 개수가 홀수
if (i % Math.sqrt(i) == 0) {
answer -= i;
}
//제곱수가 아닌 경우 약수의 개수가 짝수
else {
answer += i;
}
}
return answer;
}
}
출처:https://school.programmers.co.kr/learn/courses/30/lessons/77884/solution_groups?language=java
제곱근을 사용하셨다.
훨씬 간편한 방법인 것 같다.
가끔은 코딩 실력보다... 수학을 더 잘 알아야 할 것 같다는 생각이 든다.
일정관리 과제
필수
Lv 1. 일정 생성 및 조회 - 트러블 슈팅
전체 일정 조회(등록된 일정 불러오기)
다음 조건을 바탕으로 등록된 일정 목록을 전부 조회
- 수정일 (형식 : YYYY-MM-DD)
- 작성자명
조건 중 한 가지만을 충족하거나, 둘 다 충족을 하지 않을 수도, 두 가지를 모두 충족할 수도 있습니다.
위의 조건에 대해 잘 이해하지 못해서 선택 일정 조회부터 구현해보기로 했다.
선택 일정 조회(선택한 일정 정보 불러오기)
아래와 같은 예외가 발생했다.
2025-01-24T13:31:10.865+09:00 WARN 4241 --- [schedule] [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingPathVariableException: Required URI template variable 'id' for method parameter type Long is not present]
@PathVariable에서 ()로 url 값을 할당해주지 않았기 때문에 발생한 것으로 보인다.
출처 : https://wanggonya.tistory.com/38
@GetMapping("/{scheduleId}")
public ResponseEntity<ScheduleResponseDto> findScheduleById(@PathVariable("scheduleId") Long id){
return ResponseEntity.ok(scheduleService.findScheduleById(id));
}
아래와 같이 200 OK로 잘 나오지만
id, createdAt, updatedAt이 null로 나온다.
ResponseDto와 Mapping 관련 문제인 것으로 보인다.
public ScheduleResponseDto(Schedule schedule) {
this.id = schedule.getId();
this.todo = schedule.getTodo();
this.writer = schedule.getWriter();
this.createdAt = schedule.getCreatedAt();
this.updatedAt = schedule.getUpdatedAt();
}
ScheduleResponseDto 생성자에서 id를 설정하지 않았다.
따라서 위처럼 수정했다.
JdbcTempleteScheduleRepositoryImpl 에서 아래와 같이 설정했다.
LocalDateTime.parse(rs.getString("createdAt"))
그랬더니 아래와 같은 오류가 발생했다.
java.time.format.DateTimeParseException: Text '2025-01-23 19:18:59' could not be parsed at index 10
튜터님께 도움을 요청했고,
원인은 자바의 LocalDateTime 타입(2025-01-23T19:18:59)과
MySql의 DateTime 타입(2025-01-23 19:18:59)의
각각 형식이 달라서였다.
LocalDateTime now = LocalDateTime.now();
schedule.setCreatedAt(now); // 작성일 설정
schedule.setUpdatedAt(now); // 수정일 설정
위와 같이 설정해도, DB에는 DateTime 형식으로 들어오기 때문에 format해줘야 한다.
private RowMapper<Schedule> scheduleRowMapper() {
return new RowMapper<Schedule>() {
@Override
public Schedule mapRow(ResultSet rs, int rowNum) throws SQLException {
// 문자열을 LocalDateTime으로 변환
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return new Schedule(
rs.getLong("id"),
rs.getString("todo"),
rs.getString("writer"),
LocalDateTime.parse(rs.getString("createdAt"),formatter),
LocalDateTime.parse(rs.getString("updatedAt"),formatter)
);
}
};
}
이제는 위와 같이 잘 나오는 것을 볼 수 있다.
Lv1 전체 일정 조회(등록된 일정 불러오기)
위의 조회 부분 구현은 일단 두고 다음으로 넘어가기로 했다.
Lv 2. 일정 수정 및 삭제 - 트러블 슈팅
선택한 일정 수정
먼저 수정기능 구현이므로 PUT vs PATCH 중에서 고민하기 시작했다.
조건에는 일정, 작성자 즉, 일부만 수정할 수 있도록 구현해야 해서
PATCH를 선택했다.
위와 같이 실행하니 400 오류가 발생했다.
@Override
public int updateSchedule(Long id, String todo, String writer, String password) {
return jdbcTemplate.update("UPDATE schedule SET todo = ?, writer = ?, updatedAt = NOW()" +
"WHERE id = ? AND password = ?;",todo, writer, id, password);
}
원인은 위의 sql문에서 볼 수 있듯이, 비밀번호를 같이 입력해야 하는데 입력하지 않아서 발생한 오류였다.
비밀번호까지 입력하니 일정, 작성자, 그리고 수정일이 수정 당시 날짜과 시간으로
잘 수정된 것을 확인할 수 있다.
Lv1 전체 일정 조회(등록된 일정 불러오기)
다음 조건을 바탕으로 등록된 일정 목록을 전부 조회
- 수정일 (형식 : YYYY-MM-DD)
- 작성자명
조건 중 한 가지만을 충족하거나, 둘 다 충족을 하지 않을 수도, 두 가지를 모두 충족할 수도 있습니다.
위의 조건에 대해 이해가지 않는 부분이 있어서
튜터님께 문의를 드리고 답변을 받았다.
select *
from schedule
order by updatedAt desc
select *
from schedule
where DATE(updatedAt)=?
order by updatedAt desc
select *
from schedule
where writer=?
order by updatedAt desc
select *
from schedule
where DATE(updatedAt)=? AND writer=?
order by updatedAt desc
위의 sql문처럼 크게 4가지의 경우를 가지고
JdbcTempleteScheduleRepositoryImpl에서 각 조건에 맞는 쿼리문을 넣어주는 방법을 제안해주셨다.
password = null
일정 작성, 수정, 조회 시 반환 받은 일정 정보에 비밀번호는 제외해야 합니다.
라는 조건에 의해 해당 부분 수정이 필요했다.
public ScheduleResponseDto(Schedule schedule) {
this.id = schedule.getId();
this.todo = schedule.getTodo();
this.writer = schedule.getWriter();
this.createdAt = schedule.getCreatedAt();
this.updatedAt = schedule.getUpdatedAt();
}
ScheduleResponseDto에 위의 코드처럼 생성자로 비밀번호를 제외하고 값을 설정해주었다.
이 타입으로 반환하려고 했는데 컴파일 오류가 발생했다.
원인은 선택 일정 조회에 사용했던 RowMapper<Schedule> 타입의 메서드를 호출하려고 해서였다.
타입이 맞지 않아서 아래와 같이 타입에 맞는 새로운 메서드를 만들었다.
private RowMapper<ScheduleResponseDto> scheduleRowMapper() {
return new RowMapper<ScheduleResponseDto>() {
@Override
public ScheduleResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
// 문자열을 LocalDateTime으로 변환
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return new ScheduleResponseDto(
rs.getLong("id"),
rs.getString("todo"),
rs.getString("writer"),
LocalDateTime.parse(rs.getString("createdAt"), formatter),
LocalDateTime.parse(rs.getString("updatedAt"), formatter)
);
}
};
}
전체 일정 조회 가능
작성자로 조회가능
수정일 조회 문제 발생
Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Method parameter 'updatedAt': Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDateTime'; Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime] for value [2025-01-23]]
원인은 처음에 controller에서 파라미터로 받아온 수정일을 LocalDateTime 타입으로 설정했고,
String 타입과 달라서 오류가 발생했다.
@GetMapping
public ResponseEntity<List<ScheduleResponseDto>> findAllSchedule(
LocalDate updatedAt,
String writer
) {
log.info("updatedAt={}", updatedAt);
log.info("writer={}", writer);
return ResponseEntity.ok(scheduleService.findAllSchedules(updatedAt,writer));
}
따라서 아래와 같이 LocalDate 타입으로 매개변수를 받고,
이를 toString()을 통해 String으로 변환해서 이 값을 쿼리문에 넣어주었다.
@Override
public List<ScheduleResponseDto> findAllSchedules(LocalDate updatedAt, String writer) {
String sql;
String strUpdateAt = updatedAt.toString();
if (updatedAt != null && writer == null){
sql = "select * from schedule where DATE(updatedAt)= ? order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper(),strUpdateAt);
}
if (updatedAt == null && writer != null){
sql = "select * from schedule where writer=? order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper(),writer);
}
if (updatedAt != null && writer != null){
sql = "select * from schedule where DATE(updatedAt)=? AND writer=? order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper(),strUpdateAt,writer);
}
sql = "select * from schedule order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper());
}
그러나... 이번에는 작성자명만 입력했더니 아래와 같은 예외가 발생했다.
java.lang.NullPointerException: Cannot invoke "java.time.LocalDate.toString()" because "updatedAt" is null
원인은 String strUpdateAt = updatedAt.toString();
수정일을 파라미터로 받아오지 않을 경우 위와 같이 하면 예외가 발생했다.
따라서 아래와 같이 각 조건에 해당하는 경우에만 String으로 변환해주었다.
@Override
public List<ScheduleResponseDto> findAllSchedules(LocalDate updatedAt, String writer) {
String sql;
if (updatedAt != null && writer == null){
sql = "select * from schedule where DATE(updatedAt)= ? order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper(),String.valueOf(updatedAt));
}
if (updatedAt == null && writer != null){
sql = "select * from schedule where writer = ? order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper(),writer);
}
if (updatedAt != null && writer != null){
sql = "select * from schedule where DATE(updatedAt)=? AND writer=? order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper(),String.valueOf(updatedAt),writer);
}
sql = "select * from schedule order by updatedAt desc";
return jdbcTemplate.query(sql,scheduleRowMapper());
}
처음 과제 발제를 들었을 때에는
막막하기만 했고
필수 과제도 못할 것 같아서 두려웠는데...
그래도 오늘은 필수 과제 구현은 다했으므로
마음이 한결 놓인다.
'CODING > 스파르타 내일배움캠프 TIL' 카테고리의 다른 글
33_부족한 금액 계산하기_스탠다드 DI, IoC_일정관리 과제 Lv 4,5,6 일부 구현완료_25.1.31(금) (0) | 2025.01.31 |
---|---|
32_문자열 내림차순으로 배치하기_일정관리 과제 Lv 3 구현완료_25.1.27(월) (0) | 2025.01.27 |
30_내적_키오스크 과제 피드백_Spring 입문 6주차_일정관리 과제 Lv 0,1 구현중_25.1.23(목) (1) | 2025.01.23 |
29_수박수박수박수박수박수?_스탠다드 Spring 3 Layered, Spring MVC_Spring 입문 4,5주차_25.1.22(수) (0) | 2025.01.22 |
28_가운데 글자 가져오기_Spring 입문_25.1.21(화) (0) | 2025.01.21 |