반응형

MVC 패턴이란?

개발자가 웹 페이지를 만드는 걸 생각해보자. 서로 다른 이름을 가진 사용자 수가 3명일 때, 웹 페이지는 총 3개일...수도 있다. 하지만 만약 9999명이 된다면? 사실 100명만 되도, 개발자는 복사 붙이기(일명 복붙)을 100번 해야 하는 셈이다. 이를 해결하고자 MVC 패턴이라는 것을 만들었고, 홈페이지를 보여주는 뷰(View)와, 사용자의 요청을 서버에서 처리하는 컨트롤러(Controller), 데이터를 관리하는 모델(Model) 방식을 만들기 시작했다.

 

 

1. 뷰 템플릿 생성하기

이제, MVC 패턴을 인텔리제이 환경에서 실행해 보자. 우선, 머스태치를 활용하여 뷰 템플릿을 만든다. 여기서 머스테치란, 다양한 언어를 화면에 제공하는 템플릿 엔진이라고 생각하면 된다.

 

src -> resources -> templates -> 우클릭 new -> file 클릭 -> first.mustache 생성

 

여기서 확장자에 .mustache를 적었음에도 수염과 같은 아이콘 모양이 나오지 않아도 걱정하지 말자.

인텔리제이의 왼쪽 상단에 file -> settings -> plugin -> mustache를 클릭하여 설치해주면 된다.

 

 

자, 빈 화면이 나오지 않았는가?

여기서 doc를 누르고 tab 버튼을 누르면, 다음과 같은 html 코드가 자동으로 생성된다.

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

</body>
</html>

 

head의 <title>태그는 웹 페이지의 제목을 나타낸다. 참고로, 왼쪽에 보이는 네이버의 아이콘은 파비콘이라고 하며, 이것도 설정할 수 있으나 여기서는 생략하겠다! <title> 태그 사이에 내가 원하는 웹 페이지의 제목을 적어보자.

그리고, <body> 태그 안에 <h1> 태그를 달고, 원하는 말을 넣어보자. 필자는 이렇게 했다. 그리고 {{username}}은 변수를 받아오는 형식이다. 이를 통해, 앞서 말했던 '각 사용자 마다 페이지를 만드는 것'을 하지 않고, 원하는 변수만 바꾸어 하나의 페이지에 여러 형식을 보일 수 있다.

 

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Spring boot 연습</title>
</head>
<body>
    <h1>Hell로 월드!!!!</h1>
    <h2>{{username1}}님, 스프링 부트 열심히 하셔야죠??</h2>
    <h2>{{username2}}님, 네카라쿠배 가야죠~~</h2>
</body>
</html>

 

 

2. 컨트롤러

뷰 페이지를 설정했으니, 그 화면을 볼 수 있도록 요청을 처리해주는 컨트롤러를 만들어보자.

com.example.practice 우클릭 -> package -> com.example.practice.controller 입력 -> FirstController.class 생성

 

package com.example.practice.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller //이 객체가 컨트롤러임을 알게 해주는 어노테이션
public class FirstController {

    @GetMapping("/hi")  //URL 요청 접수
    public String helloWorld(Model model) {
        model.addAttribute("username1", "김철수");
        model.addAttribute("username2", "김영희");
        return "first"; //first 머스테치 반환
    }
}

 

여기서 @를 사용한 "어노테이션"을 볼 수 있다.

어노테이션이란, 소스 코드에 추가적으로 사용하는 메타 데이터의 일종이다. 코드를 서버에서 어떻게 처리해주어야 하는지 명시해주는 목적으로 사용된다.

 

@Controller는, 이 객체가 컨트롤러임을 명시한 어노테이션

@GetMapping("/hi")는, Client로 부터 URL을 요청 받았을 때, 아래 메소드가 실행되도록 하는 조회 어노테이션이다.

 

helloWorld 메서드의 매개변수는 Model로, MVC 패턴의 M을 담당하는 모델이다. 만약 빨간 줄이 뜬다면 alt + enter를 사용하여 import 해주면 된다. 

 

코드를 다 작성하고, 서버를 실행하면 다음과 같은 로그를 볼 수 있는데, Tomcat started on port 8081을 보면 8081 포트에서 서버가 실행된 것을 확인할 수 있다. 그러나 대부분의 사람들은 8080 포트에서 서버가 동작할 것이다. 스프링 부트는 톰캣이라는 것에 담겨서 실행되므로 다음과 같은 로그가 뜬다. 

 

localhost:8081/hi 에 접속하여 내가 원하는 뷰 페이지가 나오는지 확인해보자. 

만약 한글이 깨져서 나온다면,  src -> main -> resources -> application.properties 파일에서 다음과 같은 코드를 넣어주자.

server.servlet.encoding.force=true

 

뷰 페이지 완성

 

원하는 페이지를 출력한 것을 확인할 수 있다.

반응형
반응형

https://www.acmicpc.net/problem/2720

 

2720번: 세탁소 사장 동혁

각 테스트케이스에 대해 필요한 쿼터의 개수, 다임의 개수, 니켈의 개수, 페니의 개수를 공백으로 구분하여 출력한다.

www.acmicpc.net

문제

거스름돈의 액수가 주어지면 리암이 줘야할 쿼터(Quarter, $0.25)의 개수, 다임(Dime, $0.10)의 개수, 니켈(Nickel, $0.05)의 개수, 페니(Penny, $0.01)의 개수를 구하는 프로그램을 작성하시오. 거스름돈은 항상 $5.00 이하이고, 손님이 받는 동전의 개수를 최소로 하려고 한다. 예를 들어, $1.24를 거슬러 주어야 한다면, 손님은 4쿼터, 2다임, 0니켈, 4페니를 받게 된다.

 

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 거스름돈 C를 나타내는 정수 하나로 이루어져 있다. C의 단위는 센트이다. (1달러 = 100센트) (1<=C<=500)

 

출력

각 테스트케이스에 대해 필요한 쿼터의 개수, 다임의 개수, 니켈의 개수, 페니의 개수를 공백으로 구분하여 출력한다.

 

접근 방법

- 우선 Greedy 문제인 것을 직감적으로 알 수 있다.
입력받은 센트를 쿼터(Quarter,$0.25)로 나눴을 때 몫을 따로 저장하고, 나머지는 다시 피제수(나눠지는 수)가 된다.
그 피제수(나눠지는 수)를 다시 다임(Dime, $0.10)으로 나누고, 몫을 따로 저장하고 나머지는 다시 니켈(Nickel, $0.05)로 나눈다. 마지막으로 페니(Penny, $0.01)로 같은 작업을 반복하여  몫을 LinkedList에 저장하고 출력하면 된다.

 

정리

1. 쿼터, 다임, 니켈, 페니를 각각 25, 10, 5, 1 센트 단위로 생각하여 num배열을 하나 만든다. 그리고 몇 번 반복할지 T 값을 받는다.

 

2. 접근 방법에 해당하는 알고리즘을 구현한다.

 

3. Iterator를 사용하여 LinkedList의 원소를 출력한다.

import java.io.*;
import java.util.*;

class Main {
    public static void main(String[] args) throws IOException {

        Scanner sc = new Scanner(System.in);

        int[] num = {25, 10, 5, 1};
        int T = sc.nextInt();

//        // 1. LinkedList를 T 크기 만큼 만든다.
        LinkedList<Integer> arr = new LinkedList<>();

        for (int i = 0; i < T; i++) {
            arr.add(sc.nextInt());
        }

        // 2. for문으로 각 값의 몫과 나머지를 구한다
        for (int i = 0; i < arr.size(); i++) {
            LinkedList<Integer> li = new LinkedList<>();
            for (int j = 0; j < num.length; j++) {
                // 몫 추가
                li.add(arr.get(i) / num[j]);
                // 나머지 처리
                arr.add(i, arr.get(i) % num[j]);
                arr.remove(i + 1);
            }

            Iterator<Integer> it = li.iterator();
            while (it.hasNext()) {
                System.out.print(it.next() + " ");
            }
            System.out.println();
        }
    }
}

 

회고

- 해당 코드에서 핵심은 몫과 나머지를 어떻게 처리하냐의 문제이다. 반복 횟수가 많지는 않은데, ArrayList와 LinkedList 중 어떤 것을 써야 더 효율적일까를 고민해보았고, 물리적으로 비연속적인 LinkedList가 삽입/삭제에 더 유리하기 때문에 LinkedList를 채택했다. 사실 ArrayList를 써도 되지만, 각각의 특징을 공부하고 나니까 간단한 문제에도 이렇게 고민을 하게 되는 것 같다. 

그리고, List형태를 출력할 때 for each문 보다 Iterator를 쓰는게 효율적이라는 것을 알게 되었다. for each문은 Map클래스를 출력할 때 용이하다.

반응형
반응형

https://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

해당 내용은 위 무료 강의 내용을 수행하며, 제가 겪은 오류를 어떻게 해결하는지 정리했습니다.


강의 내용 : 섹션1. 프로젝트 환경 설정 - 프로젝트 생성

 

해당 강의에서는 spring boot 2.x.x 버젼을 사용하고 있는데, 나는 3.x.x버젼을 사용하고 있었다. 그래서 java 17 이상의 버젼이 필요했다.

 

우선 강의에 설명해주신 대로 starter.spring.io 에서 프로젝트를 생성하고 Intellij에서 프로젝트를 열었더니 아래와 같은 문구가 나오며 오류가 발생했다.

 

JDK 17 isn't compatible with Gradle 8.1.1. Please fix JAVA_HOME environment variable.

 

이 문제를, 다음과 같은 수행 절차를 통해 해결했다.

1. 환경변수 설정

2. 프로젝트 JDK 설정

 

1. 환경변수 설정

JDK 17이 Gradle 8.1.1과 호환이 안된다는 것이니, 환경변수를 설정하라는 내용이었다. 일단? 내가 알기론 Gradle 8.1.1은 JDK 17과 호환이 되는데, 왜 저런 문구가 뜨지 싶어서 환경 변수 설정을 하려고 봤는데.. 알고보니 JDK 11로 설정되어 있었다. 그래서 17로 다시 바꿔줬다.

 

환경 변수 설정하는 법

- window키 + s

- '고급 시스템 설정 보기' 검색

- 환경 변수 클릭

 

 

 

2. 프로젝트 JDK 17 변경

File -> Project Structure

 

Project SDK에서 자바 17version으로 바꿨다.

 

또한, File -> Settings -> Gradle 검색

Build and run using과 Run tests using을 Gradle에서 Intellij IDEA로 변경했다.

기본 설정값은 Gradle인데, Gradle 공식 홈페이지에서는 Gradle을 수행하는데 있어 오류가 없게 하도록 하기 위해 디폴트 값을 Gradle로 해놨다고 한다. 근데 Gradle로 컴파일 하면 속도가 느리다는 단점이 있어서, Intellij IDEA로 설정했다.

 

 

그리고 Gradle을 다시 빌드하니 오류가 나지 않았고, 해당 강의대로 (아무것도 없는)main 클래스를 실행했을 때 Tomcat이 8080포트로 시작된 것을 확인할 수 있다. 이를 확인하기 위해 localhost:8080으로 접속하면 아래와 같은 오류 페이지가 뜬다. 이로써 셋팅 완료!

 

 

 

반응형
반응형


문제 : gradle version이 달라서, compile, testCompile로 의존성을 설정하는 것이 안될 때.

 

결론 : 

compile은 implementation으로, testCompile은 testImplementation으로 변경하면 된다.

gradle 7.0 부터는 compile과 runtime을 사용하지 않게 되었기 때문이다.

 

https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation

 

The Java Library Plugin

The Java Library plugin expands the capabilities of the Java Plugin (java) by providing specific knowledge about Java libraries. In particular, a Java library exposes an API to consumers (i.e., other projects using the Java or the Java Library plugin). All

docs.gradle.org

The compile and runtime configurations have been removed with Gradle 7.0. Please refer to the upgrade guide how to migrate to implementation and api configurations`. - 출처 : gradle 공식 홈페이지 -

 

 

buildscript {
    ext {
        springBootVersion = '2.1.9.RELEASE'
    }
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group 'com.jojoldu.book'
version '1.0.4-SNAPSHOT-'+new Date().format("yyyyMMddHHmmss")
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile("org.springframework.security:spring-security-test")
}

해당 책은 gradle 4.10.2 version을 사용하고 있어서, 의존성을 추가할 때 compile, testCompile을 사용했다. 하지만, 지금은 책이 출간한지 5년 정도가 지났기에.. 나는 gradle 7.1 version을 사용하고 있었다. 그래서 위와 같은 코드를 작성했을 때 오류가 났다.

 

앞서 말한 것처럼, compile을 implementation으로, testCompile을 testImpementation으로 변경하니 빌드가 성공됐다.

 

buildscript {
    ext {
        springBootVersion = '2.1.9.RELEASE'
    }
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group 'com.jojoldu.book'
version '1.0.4-SNAPSHOT-'+new Date().format("yyyyMMddHHmmss")
sourceCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-web')
    testImplementation('org.springframework.boot:spring-boot-starter-test')
    testImplementation("org.springframework.security:spring-security-test")
}

 

여기서 의문점... 이렇게 gradle 7.1 버젼에서 빌드 하긴 했는데, 나중에 다시 다운그레이드 했을 때는 implementation이 안먹힐 줄 알았는데 그대로 적용이 됐다... 왜지..??

 

 

 

compile, testCompile에 대한 정보 출처

https://velog.io/@g0709-19/Gradle-Could-not-find-method-compile-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95

 

Gradle Could not find method compile() 해결 방법

gradle 7.0 부터 compile 명령은 삭제되었습니다.

velog.io

 

 

 

 

반응형
반응형

자바를 공부하다 보면 헷갈리는 용어가 많은데, 특히 오버로딩(Overloading)과 오버라이딩(Overriding)이 비슷해서 많이 헷갈린다. 그런데, 사실 둘은 아무 관계 없는 내용이다. 둘의 차이점을 알아보자.

 

  오버로딩(Overloading) 오버라이딩(Overriding)
접근 제어 달라도 됨 같음
반환형 달라도 됨 같음
메서드 이름 같음 같음
매개변수 달라도 됨 같음

 

1. 오버로딩(Overloading)

같은 클래스 내에서 매소드를 확장하기 위한 것. 메소드 명은 같지만, 매개 변수, 반환형 등을 다르게 하여 편리하게 사용 가능하다.

  • 메서드 이름이 같다.
  • 매개 변수, 반환형(return)은 달라도 된다. 
  • 같은 클래스 내에 선언 되어야 한다.
  • 만약 매개 변수의 개수가 같다면 자료형이 달라야 하고, 자료형이 모두 같다면 매개 변수의 개수를 다르게 해야 한다.

코드 예시를 통해 개념을 익혀보자.

class Hello {
    void overL() {
        System.out.println("오버로딩을 위한 메서드");
    }

    void overL(String str){
        System.out.println("매개 변수 타입이 String 이고, 값은 " + str);
    }

    void overL(int k){
        System.out.println("매개 변수 타입이 int 이고, 값은 " + k);
    }

    int overL(int x, int y){
        System.out.println("반환형이 다른 메서드");
        return x;
    }
}


public class HelloJava {
    public static void main(String[] args) {

        Hello ov = new Hello();

        ov.overL();
        ov.overL("오버로딩 예제");
        int num = ov.overL(5, 6);
        System.out.println(num);

    }
}

 

2. 오버라이딩(Overriding)

부모 클래스의 메서드를 자식 클래스에서 메서드를 '재정의'하는 것이다. 

  • 메서드 명, 매개 변수, 반환형, 접근 제어자가 모두 같다.
  • 상속 받은 부모 클래스의 메서드를 재정의 하는 것이다. 다른 클래스의 메서드를 재정의 하는 것이 아니다!
class Animal {
    public void makeSound() {
        System.out.println("동물이 소리를 내고 있습니다.");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("강아지가 멍멍 소리를 내고 있습니다.");
    }
}

public class HelloJava {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Dog dog = new Dog();

        animal.makeSound(); // "동물이 소리를 내고 있습니다." 출력
        dog.makeSound();    // "강아지가 멍멍 소리를 내고 있습니다." 출력

    }
}

 

반응형
반응형

프로그래머스에서 문제를 풀다가 오름차순으로 정렬할 알고리즘이 있었다.

2중 for문에 익숙한 나는, 2중 for문으로만 하려고 했는데 알고리즘을 공부하기 위해선 다양한 방법을 시도해야 했다.

그래서 Arrays.sort() 메쏘드를 사용했다.

 

 


1. 2중 for문을 사용한 오름차순 정렬
import java.util.*;

public class HelloJava {
    public static void main(String args[]) {
        
        int[] a = new int[]{1,5,4,3,2};
        int k;

        for(int i = 0; i < a.length - 1; i++){
            for(int j = i + 1; j < a.length; j++){
                if(a[i] > a[j]){
                    k = a[i];
                    a[i] = a[j];
                    a[j] = k;       
                }
            }
        }
        System.out.println(Arrays.toString(a));
    }
}

 

 

2. Arrays.sort()를 사용하여 오름차순 정렬
import java.util.*;

public class HelloJava {
    public static void main(String args[]) {
        
        int[] a = new int[]{1,5,4,3,2};
        
       	Arrays.sort(a);
        
        System.out.println(Arrays.toString(a));
    }
}

여기서 만약에

System.out.println(a);

로 값을 출력한다면 [I@24d46ca6 와 같은 배열 a의 주소값이 나올 것이다.

배열은 참조변수이므로, 배열의 원소값을 나타내기 위해서는 toString 메소드를 사용한다면 파라미터를 통해 원소 값을 문자열로 변환 후, 원소를 출력할 수 있다.

반응형
반응형

 

적용 알고리즘 : 1~6 사이의 수 중에서 나올 수를 예측하고, 실제로 나온 수와 비교하는 것이다.

 

간단하게 해결!!

 

 

//주사위 값 예측하기

import java.util.*;

class DiceGame {    // DiceGame 클래스를 생성
    
    int diceFace;
    int userGuess;

    private void RollDice() {
        diceFace = (int)(Math.random() * 6) + 1;
    }

    private int getUserInput(String prompt) {
        System.out.println(prompt);
        Scanner s = new Scanner(System.in);
        return s.nextInt();
    }

    private void checkUserGuess() {
        if (diceFace == userGuess){
            
            System.out.println("주사위 값은 " + diceFace + "이고,");
            System.out.println("내가 예측한 값은 " + userGuess + "이다.");
            System.out.println("예측 값이 맞았다!!");
        }
        else{
            System.out.println("주사위 값은 " + diceFace + "이고,");
            System.out.println("내가 예측한 값은 " + userGuess + "이다.");
            System.out.println("예측 값이 틀렸다!!");
        }
    }

    public void startPlaying() {
        userGuess = getUserInput("예상값을 입력하시오.");       //getUserInput
        RollDice();     //RollDice 메써드 실행
        checkUserGuess();       //checkUserGuess 메써드 실행
    }
}

public class DiceGameTest {
    public static void main(String[] args) {
        DiceGame game = new DiceGame();     //DiceGame 객체 생성
        game.startPlaying();
    }
}
반응형
반응형

--<백준 2475번 :: 검증수 - JAVA>--


이번 문제는 아주 간단한 문제입니다. 평소보다 문제의 길이는 길지만(?) 쉬운 알고리즘으로 풀 수 있습니다. 물론 처음 알고리즘 공부를 했을 때는 이것조차 버거웠죠.. 알고리즘 실력은 하루이틀만에 늘어나는 것이 아니니까, 차근차근 다같이 공부해봅시다.

 

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        
        Scanner input = new Scanner(System.in);

        int[] arr = new int[5];
        int cnt = 0;
        int result;

        for(int i = 0; i < arr.length; i++){
            arr[i] = input.nextInt();
            cnt = cnt + arr[i]*arr[i];
        }

        result = cnt % 10;  
        System.out.println(result);

    }
}

입력 값을 int형으로 받을 배열을 선언하고, for문에서 입력값을 받습니다. 그리고 그 값들을 제곱한 값을 cnt에 저장하고, 나중에 10으로 나눈 값을 result에 저장합니다.

간단하죠??

 

알고리즘 공부하시는 여러분, 항상 화이팅입니다!!

반응형
반응형

--<백준 1157번 :: 단어 공부 - JAVA>--


알고리즘 공부를 조금씩 하다 보니 생긴 요령이 있습니다. 영어를 앞으로 밀거나, 비교하거나, 바꾸는 경우 항상 '아스키코드'를 사용하는 것이 편리하다는 것이죠! 이번 문제도 아스키코드를 사용하여 간단하게 풀어보았습니다. 

어려운 부분은 없으니 천천히 따라오시면 됩니다!

 

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		
		Scanner input = new Scanner(System.in);
		
		int[] arr = new int[26];
		String s = input.next();
		
		for(int i = 0; i < s.length(); i++) {
			
			if(65 <= s.charAt(i) && s.charAt(i) <= 90) { // 대문자인 경우
				arr[s.charAt(i)-65]++;
			}
			else { // 소문자
				arr[s.charAt(i)-97]++;
			}
		}
		
		int max = -1;
		char ch = '?';
		
		for(int j = 0; j < 26; j++) {
			if(max < arr[j]) {
				max = arr[j];
				ch = (char)(j + 65);
			}
			else if(max == arr[j]) {
				ch = '?';
			}
		}
		
		System.out.print(ch);
	}
}

아스키코드를 참고해서 만들었습니다. 그런데 만들고보니, 다른 분과 완전 똑같게 했더라구요...

마 쉬운 문제라서 겹치는 답이지 않을까 싶습니다!!

 

알고리즘 공부하시는 분들 모두 화이팅~~

반응형
반응형

--<백준 1152번 :: 단어의 개수 - JAVA>--


총 두 가지 방법으로 풀었습니다.

 

1. StringTokenizer를 사용하는 방법

2. charAt을 사용하는 방법

 

다른 블로그를 보니까 대부분 StringTokenizer를 사용하셨더라고요! 당연히 StringTokenizer 클래스가 간단하죠. 그러나 알고리즘에 대해 아직까지는 노가다가 더 편한 저는... charAt으로도 해봤습니다. 막상 풀어보니 메모리와 시간은 비슷하더라고요! 위에가 charAt, 아래가 StringToknizer 입니다!

천천히 파헤쳐보겠습니다~

 

 


1. StringTokenizer를 활용한 자바 코드

import java.util.StringTokenizer;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		
		Scanner str = new Scanner(System.in);
		
		String s = str.nextLine();
		str.close();
		
		StringTokenizer st = new StringTokenizer(s, " ");
		
		System.out.println(st.countTokens());
	}
}

완전 간단하죠~? StringTokenizer가 띄어쓰기를 기준으로 단어를 분류하고, 그 분류된 단어들을 토큰이라고 합니다.

그 토큰의 개수만 출력해주면 바로 해결!

 


이번엔 charAt을 사용한 방법을 보여드리겠습니다.

 

2. charAt을 사용한 방법

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        
        Scanner input = new Scanner(System.in);
        String str;
        int cnt = 0;

        str = input.nextLine();

        for(int j = 0; j < str.length(); j ++){	//우선 공백의 개수를 먼저 세아린다
            if(str.charAt(j) == ' '){
                cnt++;
            }
        }

        if(str.charAt(0) != ' ' && str.charAt(str.length()-1) != ' '){ //첫 번째와 마지막이 공백이 아닌 경우
            cnt = cnt + 1; 
        }
        if(str.charAt(0) == ' ' && str.charAt(str.length()-1) == ' '){ //첫 번째와 마지막이 공백인 경우
            cnt = cnt - 1;
        }
        System.out.println(cnt);
        
    }
}

어떤 알고리즘인지 감이 오시나요??

 

아래 그림처럼 이해하면 쉽습니다!

 

우선 for문을 사용하여 공백의 개수를 cnt에 입력합니다.

 

그리고 

 

case1. 가장 첫 번째와 마지막이 공백이 아닌 경우 -> cnt = cnt + 1

case2. 가장 첫 번째와 마지막 중에서 하나만 공백인 경우 -> cnt 변화 없음

case3. 가장 첫 번째와 마지막이 모두 공백인 경우 -> cnt = cnt - 1

 

이렇게 예를 들어서 하면 쉽게 이해가 됩니다!

 

아직은 어려운 알고리즘은 아니어서 이렇게 노가다로 풀지만.... 코딩테스트나 프로그래머스에 나오는 문제들은 노가다로는 절대 안 풀리더라고요.. 하하  

 

코딩러들 다들 화이팅~!

 

반응형

+ Recent posts