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

 

코딩테스트 연습 - 완주하지 못한 선수

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다. 마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수

programmers.co.kr

 

참가자 배열 String[] participant, 완주자 배열 String[] completion이 주어진다.

참가자들 중 완주하지 못한 선수가 1명 존재할 때 이 선수의 이름을 반환하는 문제.

해시 태그로 분류되었지만 정렬만으로도 풀 수 있다.

 

풀이 1. 

import java.util.*;

class Solution {
    public String solution(String[] participant, String[] completion) {
        String answer = "";
        Arrays.sort(participant);
        Arrays.sort(completion);

        for(int i = 0; i < completion.length; i++) {
            if(!participant[i].equals(completion[i])) {
                answer = participant[i];
                break;
            }
            
            // completion의 마지막까지 전부 같다면 남은 한 명이 정답
            if(i == completion.length - 1) {
                answer = participant[i + 1];
            }
        }
        return answer;
    }
}

Arrays.sort()를 사용해 두 배열을 모두 정렬한 후 원소들을 차례로 비교한다.

다른 원소가 등장하는 순간 그 놈이 정답. 반복 종료.

마지막 원소까지 모두 같다면 participant에 남은 마지막 원소가 정답.

 

 

풀이 2.

import java.util.*;

class Solution {
    public String solution(String[] participant, String[] completion) {
        String answer = "";
        Map<String, Integer> hm = new HashMap<String, Integer>();

        // 참가자 수만큼 value 증가
        for(String p : participant) {
            // 동명이인을 고려해야한다
            if(hm.get(p) == null) {
                hm.put(p, 1);
            }else {
                hm.put(p, hm.get(p) + 1);
            }
        }

        // 완주자 수만큼 value 감소
        for(String c : completion) {
            hm.put(c, hm.get(c) - 1);
        }

        // value가 1인 key가 정답
        for(String key : hm.keySet()) {
            if(hm.get(key) == 1) {
                answer = key;
                break;
            }
        }
        return answer;
    }
}

HashMap 사용한 풀이.

참가자 수만큼 Map.entry의 value를 1씩 증가시킨다. 이때 동명이인 존재하는 경우까지 고려해야한다.

그 후 완주자 수만큼 value를 1씩 뺀다.

value가 1인 key가 완주하지 못한 선수.

'알고리즘 문제 > 프로그래머스' 카테고리의 다른 글

[PG] 기능 개발 JAVA  (0) 2020.12.28
[PG] 주식 가격 JAVA  (0) 2020.12.28
[PG] 베스트 앨범 JAVA  (0) 2020.12.28
[PG] 위장 JAVA  (0) 2020.12.27
[PG] 전화번호 목록 JAVA  (0) 2020.12.27

기본적인 예제를 위한 도메인, 레포지터리를 만든다.

도메인 : 비즈니스의 메인 객체 (ex, 회원, 주문 등). VO객체와 다른 것인지는 답변 보고 다시 수정

레포지터리 : 디비에 접근하여 도메인 객체를 관리. DAO객체와 다른 것인지는 답변 보고 다시 수정

 

도메인 객체는 VO와 똑같이 만들었다.

레포지터리도 DAO와 똑같이 만들었다. (단, 디비는 사용하지 않고 메모리에 저장하는 식으로 만듦. 나중엔 디비까지 사용할듯)

 

test패키지(?)에 repository 패키지를 따로 만들었다.

이 안에 JUnit 테스트 실행할 RepositoryTest 클래스 생성

 

Repository 클래스에 있는 모든 함수에 대한 테스트함수를 하나씩 만든다.

모든 테스트 함수는 @Test 어노테이션으로 표시한다. 

테스트함수는 함수 개별적으로도 클래스 전체적으로도 테스트가 가능하다.

테스트함수에서 Assertions.assertThan(o1).isEqualTo(o2) 를 적극적으로 사용한다. 예상 결과와 실제 결과가 일치하는지 확인하기 위함.

static import를 통해 assertThat() 바로 호출도 가능하다. (Alt + Enter -> static import) 

 

클래스 전체적으로 테스트를 수행할 경우 테스트 함수들의 호출 순서는 보장되지 않는다. 따라서 메모리가 겹쳐 잘못된 결과를 초래할 수 있다. 이를 막기 위해 @AfterEach를 사용한다.

 

@AfterEach는 각각의 테스트함수가 실행된 뒤 불려오는 콜백메서드를 위한 어노테이션이다.

이 콜백메서드는 메모리를 비우는 등의 동작을 수행하여 테스트함수의 결과가 겹치지 않도록 하는 역할을 수행한다.

 

 

 

 

출처 : www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

@ResponseBody 를 통해 API 방식으로 response처리를 할 수 있다.

@GetMapping("hello-string")
    @ResponseBody  // html의 <body>가 아니라 HTTP의 body에 return값을 직접 넣겠다는 의미
                   // html 태그를 통해 전달하는 것이 아니라 문자열만 그대로 보내는 것
    public String helloString(@RequestParam("name") String name) {
        return "hello " + name;
    }

    @GetMapping("hello-api")
    @ResponseBody  // 이렇게 객체를 넘기게 되면 JSON 형식으로 화면에 띄워준다
    public Hello helloApi(@RequestParam("name") String name) {
        Hello hello = new Hello();
        hello.setName(name);
        return hello;
    }


    static class Hello {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

String을 그대로 띄워주는 방식은 거의 사용하지 않는다.

대부분이 객체를 전달하는 방식으로 사용된다.

 

@GetMapping에 의해 helloApi()가 호출되고 @ResponseBody에 의해 helloApi()의 return값을 그대로 HTTP body에 띄워준다.

이떄 return값에 따라 각각 다른 Converter가 작동한다.

객체가 return되면 MappingJackson2HttpMessageConverter가 작동하는 것으로 기본 등록되어있다.

(Jackson : 객체 -> JSON으로 변환해주는 라이브러리)

 

 

 

출처 : www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8

(05)

정적 컨텐츠만을 위한 html 파일은 resouces::static 하위에 생성한다. 여기서 동적 프로그래밍은 불가.

 

정적 컨텐츠 hello-static.html이 불려오는 과정

->

localhost:8080/hello-static.html 요청이 들어오면 우선 @Controller에서 @GetMapping("hello-static")이 있는지를 찾는다.

이 과정에서 관련 Controller를 찾지 못할 경우 resoures: static/hello-static.html을 찾아 정적 컨텐츠를 반환한다.

 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

 

(06)

@RequestParam("~~")은 쿼리스트링의 명확한 입력을 위해 사용한다.

 

1. @RequestParam을 쓰지 않아도 쿼리스트링으로 받은 값을 사용할 수 있다.

-> 쿼리스트링 : ~~?name=asdf,   public String helloMvc(String name)  이 경우 String name에 asdf이 전달됨.

-> 단, 쿼리스트링의 key값이 String name과 다를 경우(name이 아닐 경우) String name에는 null이 전달됨.

->ex,       ~~?nme=asdf,  public String helloMvc(String name) -> String name == null

 

 

2. 영한님의 두번째 답변처럼(www.inflearn.com/questions/110832) @RequestParam 뒤에 오는 String name은 컴파일 이후 변수명이 변경되어 혼동을 초래할 수 있음. 이를 방지하기 위해 @RequestParam("name")으로 쿼리스트링의 key값은 name이라는 것을 명확하게 표현.

-> @RequestParam("name")을 사용했을 경우 쿼리스트링에서는 반드시 ~~?name=asdf으로 사용하여야 함.

-> 만약 @RequestParam("name") String nme 이 상황에서 ~~~?nme=asdf으로 받으면 에러 발생. RequstParam을 썼으면 반드시 RequestParam과 key값을 맞춰야 함.

-> RequestParam없이 그냥 String name만 했을 때는 이름을 다르게 받으면 그냥 null값이 전달되었으나 RequestParam을 사용했을때 이름을 다르게 받으면 null전달이 아니라 에러가 뜨는 이유?

-> 이건 본인의 추측인데 아마 RequestParam은 key값을 명확하게 하기 위한 용도로 명시된 key값을 반드시 사용해야만 한다는 강제성을 부여하는듯. 반드시 사용해야하는 key값을 사용하지 않았기 때문에 null전달이 아니라 에러 발생한 것.

(추측이 아니라 팩트 맞네요. @RequestParam의 required 변수의 기본값이 true였네요.)

 

 

3. @RequestParam 안에 다른 매개변수들이 들어올 수도 있음. 

-> @RequestParam(name, defaultValue, required, value)

-> name : 강의에서 사용한 파라미터

-> defaultValue : name이 전달되지 않을 경우 전달해줄 기본값

-> required : name 값의 강제성 여부 (디폴트는 true)

-> value : name과 같은 역할을 하는 name의 alias. 단, name과 value를 동시에 쓸 수 없음. (value는 굳이 왜 만들어 놓은 것인지..?)

 

 

@RequestParam에 대한 추가 정보를 얻은 '뉴렉쳐'님의 유튜브 영상 링크를 공유합니다.

https://www.youtube.com/watch?v=aBTbtFLScC0&list=RDCMUC5-ixpj8DioZqmrasj6Ihpw&index=9&ab_channel=%EB%89%B4%EB%A0%89%EC%B2%98

https://www.youtube.com/watch?v=NlUvvtCe-6I&list=RDCMUC5-ixpj8DioZqmrasj6Ihpw&index=1&ab_channel=%EB%89%B4%EB%A0%89%EC%B2%98

 

 

 

 

출처 : www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

cmd를 통해 https://start.spring.io 에서 다운받은 프로젝트 폴더로 이동

gradle.bat을 실행시키고 build가 완료되었다. 

이 과정까지 마치면 build 디렉토리 안에 libs 폴더가 생겨야 한다고 하셨는데 찾을 수 없었다.

질문 게시판을 통해 gradlew clean build라는 명령어를 통해 libs 폴더를 생성할 수 있었다. (clean으로 build하면 기존 build폴더를 제거하고 새로 만들게 됨)

이후 libs로 이동

java -jar "libs에 있는~~.jar" 명령어를 통해 서버 띄우기에 성공했다.

실제 프로젝트에서도 .jar 파일만 복사하여 java -jar 명령어로 서버를 띄운다.

 

 

 

출처 : www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

(02)

https://start.spring.io 에서 직접 추가한 thymeleaf, web 등의 라이브러리를 사용하기 위해선 다른 라이브러리들도 필요하다.

이렇게 연쇄적으로 의존관계를 갖고 있는 모든 라이브러리를 Gradle이 알아서 가져와준다.

의존관계는 테두리의 Gradle - Dependencies에서 확인 가능 (tomcat도 여기서 자동으로 땡겨와진다)

 

 

https://spring.io 에서(project - spring boot) 스프링 레퍼런스 확인 가능. 매우 중요! 

https://thymeleaf.org/

 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

 

(03)

@SpringBootApplication과 같은 패키지이거나 그 하위 패키지여야만 스프링이 인식할 수 있다.

 

url : /hello를 요청하면 @GetMapping("hello")를 인식하여 메서드를 호출한다.

이 메서드가 return한 String값을 사용해 resources::templates/return한 String값.html 페이지를 호출하는 일을 thymeleaf가 해준다. 

 

<p th:text="'안녕하세요. ' + ${data}">안녕하세요, 손님.</p>

위 코드는 그냥 로컬 경로 그대로 접근해서 열면 태그 사이의 "안녕하세요, 손님."이 화면에 나온다.

타임리프가 템플릿 엔진으로서의 동작을 하게 되면 태그 사이의 문장이 "'안녕하세요. ' + ${data}"로 치환되어 나오게 된다. (즉, 실제 서버를 통해서 띄워진 화면에서 "안녕하세요, 손님."은 보이지 않는다.)

 

출처 : www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

https://start.spring.io 스프링 프로젝트를 쉽게 만들어주는 페이지. 필요한 설정을 완료한 프로젝트를 다운받아 IDE에서 사용할 수 있다.

(IDE에서 다운받은 프로젝트의 build.gradle을 열면 된다.)

 

Maven, Gradle : 개발에 필요한 라이브러리를 가져오고 빌드에 대한 라이프 사이클을 관리해주는 툴

과거에는 Maven을 많이 사용했으나 요즘 추세는 Gradle

 

thymleaf : html을 만들어주는 템플릿 툴

 

file - settings - gradle검색 - gradle JVM을 11버전으로 변경하여 jdk 버전을 맞춰주었다.

 

main이 run 되지 않는 문제 발생. 이클립스에서 사용하던 tomcat이 완전히 종료되지 않아 8080포트를 사용할 수 없었다.

관리자 권한으로 8080포트를 사용하는 프로세스를 종료한 후 정상 작동하는 것을 확인할 수 있었다.

 

 

 

 

출처 : www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8

김영한님의 인프런 강의 "스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술"에 대한 공부 내용 정리입니다.

 

출처 표시와 함께 블로그 업로드에 대한 강의자의 허락을 미리 구했음을 밝힙니다.

 

www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8

+ Recent posts