728x90

백견불여일타 JSP& Servlet 책 공부를 마치고 

마지막 장에 MVC패턴에 대한 소개가 나왔다. 그 내용을 정리해보겠다~!

(jsp, servlet 공부하느라 적어놓은 것도 블로그에 올려야겠다!)

 

MVC 패턴(= model 2 방식)이란?

초창기 웹 애플리케이션을 작성하는 방식이 model1 이라고 한다. 

model1은 보여주는 화면단 프레젠테이션 로직과 비즈니스 로직단이 엉켜있는 방식이다. 

 

재사용성과 가독성을 위해 비즈니스 로직을 중심으로 하는 model 2방식이 나왔다.

 

model, view , controller 를 사용하는 패턴을 말한다. 

이 3가지 영역으로 나누고 이들의 결합도를 최소화하는 것이 MVC 패턴의 목표이다.

 

모델은 비즈니스 로직, 즉 데이터베이스와 연동하여 서비스를 동작하기 위한 로직을 말하고 

뷰는 결과를 출력하여 보여주는 화면단

컨트롤러는 모델과 뷰를 연결하고 제어하는 역할을 한다. 

이 책에서는 JSP 가 뷰 역할을 해서 화면에 결과물을 출력했고 

서블릿을 이용해 클라이언트의 요청을 받아 로직을 수행했다.

모델은 데이터베이스와 연동하는 비즈니스 로직을 통해 얻어온 데이트를 저장하는 용도로 사용한다. 

 

MVC 패턴의 동작원리는 다음과 같다. 

 

가장 중요한 것은 컨트롤러의 역할!

프로그램에서 컨트롤러는 요청에 따라 어떤 비즈니스 로직을 행해야하는지 결정해주는 역할을 한다. 

또한 모델을 통해 얻은 결과를 어떤 뷰에 보내서 처리할지도 결정한다. 

 

용어를 정리해보자면,

 

DAO란? Data access object 

데이터 접근 객체. 

즉 데이터베이스를 연결하는 역할을 한다. 

연결하고 연결을 끊고. 데이터베이스에 접속해서 처리할 작업들을 하는 객체이다. 

실습 때는 반복적으로 하는 디비연결, 연결 끊기는 별도의 DBManager 객체를 만들어 호출해 사용했다. (싱글톤으로! - 객체를 한번만 사용해서 기존에 생성된 인스턴스를 통해 연결..)

 

DAO 안에서 sql 쿼리를 날렸다.

 

DTO란? Data Transfer object

데이터 전송 객체 

 

나도 헷갈리는 것이 있는데 실습할 때는 VO 객체를 만들고 구현했기 때문에 

DTO와 VO의 구분이 가질 않았다. 책에서도 DTO라고 적고 VO로 사용한 것 같은데..

 

DTO와 VO의 특성을 알고 

어떤 걸 사용할지 고민하면 된다. (알고 보니 실습에서는 VO라고 하고 setter를 사용한 것을 보니 DTO로 쓴 듯하다.)

 

DTO 와 VO의 차이점

둘다 데이터를 다루지만 그 쓰임새가 다르다. 

 

결론적으로 보면

사용목적은 다르지만 사용하는 방식은 비슷해서 혼돈이 온다.

 

VO는 비즈니스 로직을 위한 데이터 상태를 처리하기 위해 주로 쓰여서

로직을 추가할 수 있고 getter 만 사용해 그 자체 값을 가져오고

( VO는 equals, hashcode를 재정의하여 사용해 객체의 주소값 상관없이 

내용이 같다면 동일하다고 본다. )

 

DTO는 데이터 전송에 주로 쓰이고

로직을 추가할 수 없고 setter, getter 를 쓴다는 차이가 있다.  

 

 

아래 코드를 통해 어떻게 사용하는지 살펴보자

 출처 chatgpt

 

 

VO (Value Object)는 주로 데이터의 상태를 나타내고 비즈니스 도메인의 특정 비즈니스 로직을 위해 사용됩니다. 다음은 DTO 대신 VO를 사용하는 경우의 예시와 상황입니다:

1. 도메인 모델 내부에서 사용하는 데이터: VO는 도메인 모델의 일부로 사용되며, 도메인 모델 내부에서 데이터를 표현하고 비즈니스 로직을 수행하는 데 사용됩니다. 예를 들어, 주문, 제품, 고객, 계좌 등과 같은 비즈니스 엔터티의 상태를 나타내기 위해 VO를 사용할 수 있습니다. 

   public class OrderVO {
       private int orderId;
       private List<ProductVO> products;
       private CustomerVO customer;
   
       // 비즈니스 로직을 포함할 수 있음
       public void calculateTotalPrice() {
           // 제품 가격을 합산하고 총 가격을 계산
       }
   }

2. 데이터 검증 및 유효성 검사:VO는 데이터의 유효성을 검사하고 특정 규칙에 따른 검증을 수행하기 위해 사용될 수 있습니다. VO 객체는 데이터의 일관성을 보장하고 비즈니스 로직에 따라 데이터를 처리하는 데 유용합니다.

 

   public class ProductVO {
       private int productId;
       private String name;
       private double price;
   
       public void validate() {
           // 제품 데이터의 유효성을 검사하고 오류를 처리
       }
   }



3. 비즈니스 룰 적용: VO는 비즈니스 룰 및 규칙을 적용하는 데 사용될 수 있습니다. 예를 들어, 할인, 부가세 계산, 주문 처리 등과 같은 비즈니스 규칙을 VO 내에서 구현할 수 있습니다.

 

   public class OrderVO {
       private int orderId;
       private List<ProductVO> products;
       private CustomerVO customer;
   
       public void applyDiscount() {
           // 할인 규칙을 적용하여 주문 가격을 조정
       }
   }



VO는 주로 비즈니스 도메인에서 데이터의 상태와 관련된 작업을 수행하기 위해 사용됩니다. 이러한 작업은 DTO보다 비즈니스 로직과 데이터 처리에 더 중점을 둔 작업이며, VO는 이를 효율적으로 처리할 수 있는 도구로 사용됩니다.

 

 

DTO (Data Transfer Object)는 주로 데이터 전송과 다른 레이어 간의 데이터 교환을 위해 사용됩니다. 다음은 DTO를 사용하는 몇 가지 주요 상황과 예시입니다:

1. 데이터베이스와 비즈니스 레이어 간 데이터 전송:데이터베이스에서 데이터를 검색하고, 이 데이터를 비즈니스 레이어로 가져올 때 DTO를 사용합니다. DTO는 데이터베이스 스키마와 비즈니스 모델 간의 데이터 구조 차이를 처리하고 데이터를 전달하는 역할을 합니다.

   예시:

   public class ProductDTO {
       private int productId;
       private String name;
       private double price;

       // Getter 및 Setter 메서드
   }



2. 서로 다른 시스템 간 데이터 교환: 웹 서비스나 REST API를 통해 다른 시스템으로 데이터를 전송할 때 DTO를 사용합니다. 이렇게 다른 시스템 간의 통신에서는 데이터를 구조화하고 표준 형식으로 전송하기 위한 목적으로 DTO를 활용합니다.

   예시:

   public class OrderRequestDTO {
       private List<ProductDTO> products;
       private CustomerDTO customer;

       // Getter 및 Setter 메서드
   }



3. 뷰 레이어와 비즈니스 레이어 간 데이터 전송: 웹 애플리케이션에서 사용자 인터페이스와 비즈니스 레이어 사이에서 데이터를 전달할 때 DTO를 사용합니다. DTO는 뷰에서 필요한 데이터를 비즈니스 레이어로 전달하고 그 반대로 비즈니스 로직의 결과를 뷰로 반환하기 위해 사용됩니다.

   예시:

   public class OrderFormDTO {
       private String customerName;
       private List<ProductDTO> selectedProducts;

       // Getter 및 Setter 메서드
   }



4. 데이터 필터링: 뷰에서 데이터베이스로 데이터를 요청할 때, DTO를 사용하여 필요한 필드만 선택적으로 전달하는 방식으로 데이터 필터링을 수행할 수 있습니다.

   예시:
 

   public class ProductRequestDTO {
       private boolean includePrice;
       private boolean includeDescription;

       // Getter 및 Setter 메서드
   }



DTO는 주로 데이터의 전송과 데이터 구조 변환을 간소화하고 효과적으로 관리하기 위해 사용됩니다. 데이터를 읽기, 쓰기, 전송하기 위한 간편한 방법을 제공하며, 데이터의 형식이나 구조가 서로 다른 레이어 간에 호환성을 유지하는 데 도움을 줍니다.

 

 

이 둘을 어떻게 사용할지 더 물어봤다. 



여기서는 간단한 예를 통해 설명하겠습니다:

1. DTO를 사용한 접근:

   - `ProductDTO`를 사용하여 데이터베이스에서 제품 정보를 가져옵니다.
   - `OrderVO`에서 이러한 `ProductDTO`를 사용하여 제품 가격을 가져와서 총 가격을 계산합니다.

   public class OrderVO {
       private List<ProductDTO> products;

       public void calculateTotalPrice() {
           double total = 0;
           for (ProductDTO productDTO : products) {
               // ProductDTO에서 제품 가격을 가져와서 합산
               total += productDTO.getPrice();
           }
           // 총 가격을 설정
           // total 값을 다른 VO 속성에 저장
       }
   }



2. DTO를 사용하지 않는 직접적인 접근:

   - `OrderVO`에서 데이터베이스에 직접 연결하여 제품 정보를 가져와 가격을 계산합니다.

 

   public class OrderVO {
       private List<ProductVO> products;

       public void calculateTotalPrice() {
           double total = 0;
           for (ProductVO productVO : products) {
               // 데이터베이스에 연결하여 제품 가격을 가져와서 합산
               // total 값을 다른 VO 속성에 저장
           }
       }
   }


- DTO (Data Transfer Object): 데이터를 전달하고 다른 레이어 간의 데이터 교환을 목적으로 사용됩니다. 주로 데이터를 구조화하고 전달하기 위한 객체입니다.

- DAO (Data Access Object): 데이터베이스와 상호 작용하여 데이터를 검색, 추가, 수정, 삭제하는 역할을 합니다. 데이터베이스 액세스와 데이터 관리를 위한 객체입니다.

- VO (Value Object):주로 비즈니스 도메인의 상태를 나타내며, 불변하고 비즈니스 로직을 수행하기 위한 객체입니다.

일반적으로 DTO는 DAO에서 데이터베이스에서 가져온 데이터를 비즈니스 레이어로 전달할 때 사용됩니다. 이후 비즈니스 로직은 VO나 다른 비즈니스 객체에서 처리됩니다. VO와 DTO는 각각의 역할과 목적을 갖고 있으며, 이러한 분리된 역할은 코드의 가독성, 유지보수성, 테스트 용이성을 개선하는 데 도움을 줍니다.

 

 

 

 

 

 

 

https://velog.io/@gillog/Entity-DTO-VO-%EB%B0%94%EB%A1%9C-%EC%95%8C%EA%B8%B0

728x90
728x90

자바 프로젝트를 데이터베이스에 연결하기 위해서는 다음과 같은 단계를 거친다. 

1. JDBC 드라이버 로드  (JDBC java Database Connectivity 자바와 디비 연결을 돕는 api들을 제공해준다)

2. 데이터베이스와 연결

3. SQL문 실행

4. 데이터베이스와 연결 끊음

 

나는 1번부터 막혔다! (이클립스에서 인텔리제이로 넘어오면서 책에 예시가 없어서 다 찾아봐야했다)

maven이나 gradle을 써서 사용하는 드라이버 설정을 해줘야하나 싶었지만 역시나 해결이 안됨.

 

마리아 디비 드라이버 다운 

https://mariadb.com/downloads/connectors/connectors-data-access/java8-connector

+ java 눌러서 다운받은 드라이버넣어줬는데도

Class.forName("org.mariadb.jdbc.Driver");

부터 통과가 안됐다! 드라이버를 못가져오는거같은데...

 

 

해결방법

 

이 블로그를 보고 도움 받았다!

"WEB-INF/lib 안에 mariadb-java-client-2.6.2.jar을 빌드 해주야 해결이 된다" !

https://jung-story.tistory.com/108

 

Avaliable Elements 안에 TEST 안에 있는 

maraidb 파일을 클릭해서 왼쪽 lib 안에 집어넣는다.

 

드라이버 연결 DBManager

 

package util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class DBManager {
    public static Connection getConnection(){


        Connection con = null;

        String server = "서버주소(나는 localhost)";
        String database = "데이터베이스 이름";
        String user_name = "유저네임";
        String password = "비밀번호";

        try {
            Class.forName("org.mariadb.jdbc.Driver");
            System.out.println("드라이브로드 성공");

        } catch (ClassNotFoundException e) {
            System.err.println(" 드라이버 로딩 오류 : " + e.getMessage());
            e.printStackTrace();
        }

        try {
            con = DriverManager.getConnection("jdbc:mariadb://" +
                    server + "/" +
                    database +
                    "?useSSL=false", user_name, password); // SSL 실행 확인
            System.out.println("연결 성공");
        } catch(Exception e) {
            System.err.println("에러 내용 :" + e.getMessage());
            e.printStackTrace();
        }

        System.out.println("con리턴" +con);
        return con;



    }
    //select 수행한 후 리소스 해제를 위한 메소드
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        try{
            rs.close();
            stmt.close();
            conn.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //insert, update, delete 작업을 수행한 후 리소스 해제를 위한 메소드
    public static void close(Connection conn, Statement stmt){
        try{
            stmt.close();
            conn.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

ProductDAO

에서 getInstance를 통해 연결!

package com.saeyan.dao;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import util.DBManager;

import com.saeyan.dto.ProductVO;

public class ProductDAO {
    private ProductDAO(){

    }
    private static ProductDAO instance = new ProductDAO();
    public static ProductDAO getInstance(){
        return instance;
    }

    //c Read u d
    public  List<ProductVO> selectAllProducts(){
        //최근 등록한 상품 먼저 출력하기
        String sql= "select * from product order by code desc";
        List<ProductVO> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try{
            conn = DBManager.getConnection();
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();


            while (rs.next()){
                ProductVO pVo = new ProductVO();
                pVo.setCode(rs.getInt("code"));
                pVo.setName(rs.getString("name"));
                pVo.setPrice(rs.getInt("price"));
                pVo.setPictureUrl(rs.getString("pictureurl"));
                pVo.setDescription(rs.getString("description"));

                list.add(pVo); //앗 얘를 빼먹었었네!
            }


        } catch(Exception e){
            System.out.println("값 못가져옴:"+e.getMessage());


        } finally {
            DBManager.close(conn, pstmt, rs);
        }
        return list;
    }

}
728x90
728x90

모던자바인액션을 읽으며

순차 스트림, 병렬 스트림을 배우면서 

"무엇보다 컴퓨터의 멀티 코어를 활용해서 파이프라인 연산을 실행할 수 있다는 점이 중요한 특징이다."

"따라서 병렬 스트림을 이용하면 멀티코어 프로세서가 각각의 청크를 처리하도록 할당할 수 있다."

라는 말이 멈칫했다. "멀티코어"를 사용한 적이 있었나..? 

 

스레드풀 배우면서 자바는 멀티스레드를 쓰는 구나~ 이해하고 넘어가서 

멀티 코어가 자꾸 등장해서 혼란스러웠다

 

나의 혼란의 원인은 병렬처리의 중복된 용어 사용이었다. chatgpt와 질의응답을 한 내용으로 정리해본다. 

(멀티 스레드: 스레드가 여러개 , 멀티 코어: 코어가 여러개 (cpu))

 

 

 

싱글 코어에서 멀티 스레드로 처리되는 경우는 결국 스레드가 순차적으로 실행되는거야?

 

싱글 코어에서 멀티 스레드를 사용하는 경우, 스레드는 하나의 코어에서 실행됩니다. 이렇게 되면 스레드들은 시분할 방식으로 번갈아가며 실행되기 때문에 동시에 여러 스레드가 병렬적으로 실행되는 것처럼 보일 수 있지만, 사실은 순차적으로 실행됩니다. 이것을 "멀티 스레딩"이라고 합니다.

싱글 코어에서 멀티 스레딩을 사용하면 스레드 간에 시간을 나눠 가지며 작업을 처리하기 때문에 병렬 처리를 하는 것보다는 성능 향상이 제한적일 수 있습니다. 진정한 병렬 처리를 위해서는 멀티 코어 CPU가 필요하며, 각각의 코어에서 별도의 스레드를 동시에 실행할 수 있어야 합니다.

 

그렇다면 스레드풀은 싱글코어에서도 가능하고 멀티코어에도 가능한 멀티 스레드를 만드는 기능인거야?

 

네, 스레드 풀은 싱글 코어 및 멀티 코어 환경에서 모두 사용할 수 있는 멀티 스레딩을 구현하는 데 도움을 주는 기능입니다. 스레드 풀은 스레드를 효율적으로 관리하고 재사용하는 데 도움을 줍니다.

스레드 풀은 스레드를 미리 생성하고 풀에 보관해두고, 작업이 필요할 때 이 풀에서 스레드를 가져와 작업을 실행하고 다시 풀에 반환하는 방식으로 동작합니다. 이렇게 하면 스레드를 반복적으로 생성하고 제거하는 오버헤드를 피하고, 스레드의 재사용을 통해 성능을 향상시킬 수 있습니다.

따라서 싱글 코어 또는 멀티 코어 시스템에서 스레드 풀을 사용하여 멀티 스레딩을 구현할 수 있으며, 이를 통해 작업을 병렬로 처리할 수 있습니다.

 

(오버헤드: 추가 처리 작업에 드는 비용)

 

병렬로 처리한다는 말이 싱글코어와 멀티코어 모두에서 쓸 수 있는 말이야?

 

"병렬로 처리한다"는 말은 원칙적으로 싱글 코어와 멀티 코어 모두에서 사용할 수 있는 말입니다. 그러나 실행 환경에 따라 실제로 얼마나 효과적으로 병렬로 처리되는지는 다를 수 있습니다.

  • 싱글 코어: 싱글 코어에서 병렬 처리라고 말하더라도, 이것은 스레드가 시분할 방식으로 번갈아가며 실행되는 것을 의미합니다. 따라서 실제로는 동시에 여러 작업을 처리하는 것이 아니라 스레드 간에 작업을 번갈아가며 처리합니다. 이로 인해 싱글 코어에서는 병렬 처리의 이점을 크게 누리기 어렵습니다.
  • 멀티 코어: 멀티 코어 CPU에서 병렬 처리는 실제로 여러 코어에서 병렬로 실행되는 작업을 의미합니다. 각 코어는 독립적으로 작업을 처리하므로 실제로 병렬 처리의 이점을 제대로 누릴 수 있습니다. 멀티 스레딩 및 멀티 프로세싱 기술을 사용하여 멀티 코어 시스템에서 병렬 처리를 구현할 수 있습니다.

따라서 "병렬로 처리한다"는 말 자체는 두 환경에서 모두 사용할 수 있지만, 싱글 코어에서는 실제로 병렬 처리의 성능 향상을 기대하기 어렵습니다. 멀티 코어 시스템에서 이 말이 더 효과적으로 적용됩니다.

 

멀티 프로세서와 멀티 코어는 같은 말이야 다른 말이야?

 

멀티 프로세서와 멀티 코어는 비슷한 개념이지만 약간의 차이가 있습니다.

1. 멀티 프로세서(Multi-Processor):
   - 멀티 프로세서는 여러 개의 독립적인 중앙 처리 장치(CPU) 또는 프로세서를 포함하는 컴퓨터 시스템을 나타냅니다. 각 프로세서는 별도의 작업을 처리하며, 이들은 주로 병렬 컴퓨팅 및 서버 환경에서 사용됩니다.
   - 멀티 프로세서 시스템은 여러 개의 물리적 CPU 칩 또는 소켓을 가질 수 있으며, 각각의 CPU는 독립적인 처리 유닛을 가집니다.

2. 멀티 코어(Multi-Core):
   - 멀티 코어는 하나의 CPU 칩 내에 여러 개의 실행 코어(중앙 처리 장치 코어)가 내장된 프로세서를 나타냅니다. 이러한 코어들은 하나의 CPU 칩 내에서 서로 공유된 리소스를 사용하며, 병렬로 여러 작업을 처리할 수 있습니다.
   - 멀티 코어 프로세서는 물리적 CPU 칩 하나에 여러 개의 논리적 코어를 가지고 있으며, 이러한 코어들은 주로 개인용 컴퓨터 및 노트북과 같은 일반적인 컴퓨터 시스템에서 사용됩니다.

요약하면, 멀티 프로세서는 여러 개의 독립적인 CPU를 가진 전체 시스템을 나타내는 것이고, 멀티 코어는 하나의 CPU 칩 내에 여러 개의 코어가 있는 프로세서를 나타냅니다. 둘 다 병렬 처리를 가능하게 하며 성능을 향상시키지만, 멀티 코어는 일반적으로 개인용 컴퓨터 및 모바일 기기에서 더 일반적으로 사용됩니다.

728x90
728x90

출처 : 자바의 신, The Java™ Tutorials



컬렉션은 목록성 데이터를 처리하는 자료구조를 통칭한다.

컬렉션(때때로 컨테이너라고도 함)은 단순히 여러 요소를 단일 단위로 그룹화하는 개체입니다. 컬렉션은 집계 데이터를 저장, 검색, 조작 및 전달하는 데 사용됩니다. 일반적으로 포커 핸드(카드 모음), 메일 폴더(편지 모음) 또는 전화번호부(이름과 전화번호 매핑)와 같이 자연스러운 그룹을 형성하는 데이터 항목을 나타냅니다.

 

자료구조: Data Structure 여러 데이터를 담을 때 사용

(만약 컬렉션이 아닌 배열에 데이터를 담는다면 배열의 크기를 미리 정해놔야해서 비효율적이고 메모리 낭비가 발생할 수 있다.)

 

자료구조 중에서 저장순서가 중요한 것은 List와 Queue 뿐이다. 

  1. 순서가 있는 목록인 List 형 : 순서가 중요한 데이터 담기에 좋다. 중복 저장이 가능하다.
  2. 순서가 중요하지 않은 목록인 Set형 : 순서 상관없이, 중복되는 것을 방지, 원하는 값이 포함되어있는지 확인이 주 용도
  3. 먼저 들어온 것이 먼저 나가는 Queue형
  4. 키key 값value으로 저장되는 Map형

핵심 컬렉션 인터페이스

Collection— 컬렉션 계층 구조의 루트입니다. 컬렉션은 해당 요소로 알려진 개체 그룹을 나타냅니다. Collection 인터페이스는 모든 컬렉션이 구현하는 최소 공통 분모이며 최대 일반성이 필요할 때 컬렉션을 전달하고 조작하는 데 사용됩니다. 일부 유형의 컬렉션에서는 중복 요소를 허용하고 다른 컬렉션에서는 허용하지 않습니다. Java 플랫폼은 이 인터페이스의 직접적인 구현을 제공하지 않지만 Set 및 List와 같은 보다 구체적인 하위 인터페이스의 구현을 제공합니다.

Set세트 집합— 중복된 요소를 포함할 수 없는 컬렉션입니다. 이 인터페이스는 수학적 집합 추상화를 모델링하고 포커 핸드를 구성하는 카드, 학생의 일정을 구성하는 코스 또는 기계에서 실행되는 프로세스와 같은 집합을 나타내는 데 사용됩니다. 

List목록 — 순서가 지정된 컬렉션(때때로 시퀀스라고도 함)입니다. 목록에는 중복된 요소가 포함될 수 있습니다. 목록 사용자는 일반적으로 목록의 각 요소가 삽입되는 위치를 정확하게 제어할 수 있으며 정수 인덱스(위치)로 요소에 액세스할 수 있습니다. Vector를 사용해 본 적이 있다면 List의 일반적인 특징에 익숙할 것입니다. 

Queue대기열 — 처리 전에 여러 요소를 보유하는 데 사용되는 컬렉션입니다. 기본 컬렉션 작업 외에도 대기열은 추가 삽입, 추출 및 검사 작업을 제공합니다. 대기열은 일반적으로 FIFO(선입선출) 방식으로 요소를 정렬하지만 반드시 그럴 필요는 없습니다. 예외 중에는 제공된 비교기 또는 요소의 자연 순서에 따라 요소를 정렬하는 우선순위 큐가 있습니다. 어떤 순서를 사용하든 대기열의 헤드는 제거 또는 폴링 호출에 의해 제거되는 요소입니다. FIFO 대기열에서는 모든 새 요소가 대기열의 꼬리에 삽입됩니다. 다른 종류의 대기열은 다른 배치 규칙을 사용할 수 있습니다. 모든 대기열 구현은 순서 속성을 지정해야 합니다

Map키를 값에 매핑하는 객체입니다. 맵에는 중복 키가 포함될 수 없습니다. 각 키는 최대 하나의 값에 매핑될 수 있습니다. Hashtable을 사용해 본 적이 있다면 이미 Map의 기본 사항에 익숙할 것입니다. 

마지막 두 개의 핵심 컬렉션 인터페이스는 단순히 Set 및 Map의 정렬된 버전

SortedSet — 요소를 오름차순으로 유지하는 Set입니다. 주문을 활용하기 위해 몇 가지 추가 작업이 제공됩니다. 정렬된 집합은 단어 목록 및 회원 목록과 같이 자연스럽게 정렬된 집합에 사용됩니다. 
SortedMap — 오름차순 키 순서로 매핑을 유지하는 맵입니다. 이것은 SortedSet의 Map 아날로그입니다. 정렬된 맵은 사전 및 전화번호부와 같이 자연스럽게 정렬된 키/값 쌍 컬렉션에 사용됩니다. 

 

 

자바에는 List, Set, Queue는 Collection이라는 인터페이스를 구현하고 있다.

Map은 Collection과 관련없는 별도의 인터페이스를 구현하고 있다.

 

List 인터페이스 : 구현 클래스 ArrayList , Stack

 

Set 인터페이스 : 구현 클래스 HashSet , TreeSet, LinkedHashSet

  1. HashSet 순서필요없는 데이터를 해시테이블에 저장한다. set중에 성능이 가장 좋다.
  2. TreeSet 저장된 데이터의 값에 따라 정렬되는 set. 레드블랙 트리타입으로 값 저장, hashSet보다는 약간 성능 느리다.
  3. LinkedHashSet 연결된 목록 타입으로 구현된 해시테이블에 데이터를 저장한다. 저장된 순서에 따라 값 정렬된다, 대신 성능이 가장 느리다.

 

Map 인터페이스 : 구현 클래스 HashMap, TreeMap, LinkedHashMap ,HashTable

  • HashTable클래스는 Map 인터페이스를 구현하기는 했지만 일반적인 Map 인터페이스를 구현한 클래스들과는 다르다. 
    • Map은 컬렉션 뷰 collection view를 사용하지만 , Hashtable은 Enumeration 객체를 통해서 데이터를 처리한다.
    • Map은 키, 값, 키-값 쌍으로 데이터를 순환하여 처리할 수 있지만 Hashtable은 이중에서 키-값 쌍으로 데이터를 순환하여 처리할 수 없다. 
    • Map은 이터레이션을 처리하는 도중에 데이터를 삭제하는 안전한 방법을 제공하지만, Hashtable은 그러한 기능을 제공하지 않는다. 
기능 HashMap Hashtable
키나 값에 null 저장 가능 여부 가능 불가능
여러 쓰레드에서 동시 접근 가능 여부 불가능 가능

 

Hashtable을 제외한 Map으로 끝나는 클래스들을 여러 쓰레드에서 동시에 접근하여 처리할 필요가 있을 때는 다음과 같이 선언하여 사용한다. 

Map m = Collections.synchronizedMap(new HashMap(...));

 

 

HashMap의 키는 기본 자료형, 참조 자료형 모두 될 수 있지만 주로 int, long나 String 클래스를 키로 많이 사용한다. 

만약 직접 어떤 클래스를 만들어 키로 사용한다면 Object 클래스의 hashCode() 메소드와 equals() 메소드를 잘 구현해 놓아야만 한다!!

 

HashMap에 객체가 들어가면 hashCode() 메소드의 결과 값에 따른 버켓(bucket)이라는 List형태의 저장소가 만들어진다. 만약 서로 다른 키가 저장되었는데 hashCode() 메소드의 결과가 동일하다면 이 버켓에 여러 개의 값이 들어갈 수 있다. 따라서 get()메소드가 호출되면 hashCode()의 결과를 확인하고 버켓에 들어간 목록에 데이터가 여러 개일 경우 equals() 메소드를 호출해 동일한 값을 찾게 된다. 

자세한 내용은 java map buckets을 검색해보자 

 

TreeMap 클래스는 저장하면서 키를 정렬한다. (정렬 순서는 "숫자 > 알파벳 대문자 > 알파벳 소문자 > 한글"

 

 

728x90
728x90

https://www.baeldung.com/java-initialization

 

728x90
728x90

String 클래스의 equals()는

상위클래스인 object의 equals를 재정의한 메서드이다.

equals () 는 두 값 자체를 비교한다. 같으면 true, 틀리면 false를 리턴한다. 

 public void compareToCheck(){
        String text ="a";
        String text00 ="a";
        String text01 = new String("a");
        System.out.println(text.equals(text00));
        System.out.println(text00.equals(text01));
        
        
         if(text00 ==text01){
            System.out.println("text00 ==text01");
        } else{
            System.out.println("text00 !=text01");

        }
    }

이렇게 equals 메소드를 이용해 비교했을 때는 모두 같다고 나오지만

== 연산자로 비교시에는 객체의 주소를 비교한다.

 

그결과 다르게 나오는 이유는 자바에서 Constant pool을 이용해서 이다. 

상수값을 모아둔 pool이다. String 클래스는 불변의 immutable한 특징이 있다. 그래서 String클래스를 new 연산자를 이용해 새로운 객체를 생성하지 않는 이상, 리터럴 "" 문자 그대로의 값은 기존 상수값 메모리에 재활용된다. 

(text가 text00으로 대체되고 text는 가비지 콜렉터가 처리할 대상이된다. )

출처:

https://jiwondev.tistory.com/114

 

자바의 String과 Constant Pool

JVM에 관하여 #1. JVM 운영체제와 하드웨어에 독립적인 언어, 1995년 당시 이 개념은 프로그래밍의 혁신이었다. 참고로 자바는 썬 마이크로시스템스가 개발했지만 JVM 명세(Specification)만 따른다면 누

jiwondev.tistory.com

 

compareTo는 정렬할 때 사용한다. 

 

compareTo 매개변수로 넘겨준 String 객체가 알파벳 순으로 앞에 있으면 양수, 뒤에 있으면 음수를 리턴한다. 그리고 알파벳 순서만큼 그 숫자값은 커진다. 

    public void compareToCheck(){
        String text ="a";
        String text2 ="b";
        String text3 = "c";
        System.out.println(text2.compareTo(text));
        System.out.println(text2.compareTo(text3));
        System.out.println(text.compareTo(text3));
    }

 

예시)

value.compareTo(target)

 

1.compareTo(1):0

기존보다 target이 앞에 있는 숫자면 앞에 있는 숫자 만큼 1
2.compareTo(1):1

3.compareTo(2):1

 

기존보다 target이 앞에 있는 숫자면 뒤에 있는 만큼 -1
2.compareTo(3):-1

-- 문자도 마찬가지 알파벳으로 정렬했을 때 기준으로 비교된다. 

tempT:c
valueT:b
tempT.compareTo(valueT):1

 

tempT:a
valueT:c
tempT.compareTo(valueT):-2

 

 

 

 

compareTo<T> 인터페이스를 이용한 최대값, 최소값 구하는 코드

package GodOfJava.src.main.java.d.generic.practice;

//제네릭을 이용해라
public class MaxFinder {


    public static void main(String[] args) {
        MaxFinder maxFinder = new MaxFinder();
        maxFinder.testGetMax();


    }


    public void testGetMax(){



        System.out.println(getMax(1,2,3));
        System.out.println(getMax(3,1,2));
        System.out.println(getMax("a","b","c"));
        System.out.println(getMax("b","c","a"));
        System.out.println(getMax("a","b","c"));

        System.out.println(getMin(1,2,3));
        System.out.println(getMin(3,1,2));
        System.out.println(getMin("a","b","c"));
        System.out.println(getMin("b","c","a"));
        System.out.println(getMin("a","b","c"));




    }

    public <T extends Comparable<T>> T getMax(T ... a){
        T maxT = a[0];
        System.out.println("maxT:"+maxT);
        for (T tempT : a){
            if(tempT.compareTo(maxT) >0) maxT = tempT;
        }
        return maxT;
    }

    public <T extends Comparable<T>> T getMin(T ... a){
        T minT = a[0];

        for (T minA : a){
            if (minA.compareTo(minT) < 0) {
                minT = minA;
            }

        }
        return minT;

    }

}
728x90
728x90

인터페이스(구현을 위한 껍데기로 틀을 잡아주는 역할을 한다)와 추상 클래스(abstract 추상 메소드가 하나라도 있는 클래스)는 용도가 다르다.

 

인터페이스는 내부기능을 조작하는 접속장치, 지침서의 역할을 한다. 

추상 클래스는 추상적으로 객체의 공통되는 특징을 가져와 새로운 클래스로 만드는 용으로 쓴다.

 

인터페이스는 선언된 추상메소드들로 구현을 하기 위해 쓰이고

추상클래스는 상속을 통해 확장하기 위해 쓴다.

 

(인터페이스에 정의한 몸통이 없는 메소드가 바로 구현되지 않은 추상 메소드이다.

인터페이스를 구현해 사용하고자 하는 클래스에서 인터페이스에 정의된 메소드들을 구현해줘야 한다. implements)

 

  인터페이스 abstract 클래스 클래스
선언시 사용하는 예약어 interface abstract class class
구현 안 된 메소드 포함가능 여부 가능(필수) 가능 불가
구현된 메소드 포함 가능 여부 불가 가능 가능(필수)
static 메소드 선언 가능여부 불가  가능 가능
final 메소드 선언 가능 여부  불가  가능 가능
상속(extends) 가능 불가 가능 가능
구현(implements) 가능 가능 불가 불가

 출처: 자바의 신

 

자바에서는 단일 상속만 가능하다. 다중상속과 같은 기능을 인터페이스를 통해 구현할 수 있다.

(상속이란 부모에 선언된 변수와 메소드에 대한 사용권을 갖는 것을 말한다. extends를 사용해 확장하거나 implements를 사용해 구현한 경우가 상속에 속한다. )

 

인터페이스는 다중 구현이 가능하다. 

즉 class A에 implements 인터페이스 1, 인터페이스2,, 가 가능하다.

class A에서 인터페이스 여러 개의 추상메서드들을 사용가능한 것이다. 

인터페이스 다중 구현 시 중복된 메서드가 있으면 반드시 하위 클래스에서 재정의 해야한다.

 

 

인터페이스의 목적

1. 설계

2. 은닉 ( 클래스를 통해 실제 구현한 객체를 인터페이스 뒤에 가리고 소통한다.)

 

 

인터페이스는 그 자체로는 구현되지 않아서 인터페이스로 생성자를 불러 객체를 생성하려고 하면 컴파일 에러가 난다. 

인터페이스의 변수는 public static final로 자동선언된다. 

인터페이스의 메소드도 마찬가지로 public abstract으로 자동선언된다. 

 

? 왜 인터페이스의 변수는 static final로 선언될까 ? 

Java 인터페이스는 자체적으로 인스턴스화할 수 없기 때문에 인터페이스 변수는 정적이다. 변수의 값은 인스턴스가 존재하지 않는 정적 컨텍스트에서 할당되어야 한다. 객체 생성 시점이 아닌 컴파일 될때 메모리할당하는 static을 사용한다. 한번만 초기화하는 final을 통해 이후에도 값이 새로 할당되지 않도록 한다.

 

static과 final 개념

 

static : 고정의, 정적인

-> 값이 고정되어있다.

->해당 데이터의 메모리 할당을 컴파일 시간에 하고 프로그램이 끝날 때까지 static 데이터는 메모리 수명이 유지된다. 

-> non-static 변수는 새 객체를 생성할 때마다 초기화하고 메모리에 담는데 static변수는 계속 같은 값을 쓴다!

 

final : 최종의, 마지막의 -> 한 번만 초기화 가능하다

-> 변수로 final 선언하면 생성자나 연산자로 한번만 초기화되어 변하지 않는 상수값 할당됨

-> 클래스를 final로 선언하면 상속불가 extends X( 상속계층에서 마지막 클래스 됨)

-> 메소드를 final로 선언하면 오버라이딩 불가 @Override X

 

static final : 고정된 최종!!

-> 값을 바꿀 수 없는 상수가 된다.

-> 상수이므로 생성과 동시에 초기화가 된다. (초기화란 값을 할당)

 

 

 

참고문헌:

 

https://djkeh.github.io/articles/Why-should-final-member-variables-be-conventionally-static-in-Java-kor/

 

왜 자바에서 final 멤버 변수는 관례적으로 static을 붙일까?

자바 final, static 키워드와 코딩 best practice 되짚어보기

djkeh.github.io

 

https://stackoverflow.com/questions/2430756/why-are-interface-variables-static-and-final-by-default

 

Why are interface variables static and final by default?

Why are interface variables static and final by default in Java?

stackoverflow.com

https://byjus.com/gate/difference-between-abstract-class-and-interface-in-java/

 

Difference between Abstract Class and Interface in Java

Difference between Abstract Class and Interface in JAVA. The Abstract class and Interface both are used to have abstraction. An abstract class contains an abstract keyword on the declaration whereas an Interface is a sketch that is used to implement a clas

byjus.com

https://velog.io/@codren/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%8B%A4%EC%A4%91-%EA%B5%AC%ED%98%84%EA%B3%BC-%EC%83%81%EC%86%8D

 

인터페이스 다중 구현과 상속

인터페이스의 다중 구현과 중복 상황, 인터페이스 상속, 인터페이스 구현과 상속

velog.io

 

728x90
728x90

https://stackoverflow.com/questions/7026507/why-are-static-variables-considered-evil

 

Why are static variables considered evil?

I am a Java programmer who is new to the corporate world. Recently I've developed an application using Groovy and Java. All through the code I wrote used quite a good number of statics. I was asked...

stackoverflow.com

 

 

static은 정적의 , 고정의 라는 뜻으로 static 으로 선언되면 프로그램이 종료되기 전까지 메모리를 차지한다. 

전역변수처럼 상위에 고정되어 있다. 그래서 객체 생성 없이 꺼내서 사용하기에는 편리하나 관리하기가 불편하고 

사용하지 않을 때 가비지로 수집되지 않아 메모리 누수가 발생할 수 있다. 

객체들의 자율적인 협력을 지향하는 객체지향 프로그램에 맞지 않다. 

 

위 글에서 다시 보려고 적어둔 내용!

 

Java에서 정적 메소드를 사용할 때의 몇 가지 기본적인 장점과 단점을 요약하면 다음과 같습니다.

장점:

  1. 전역적으로 액세스 가능합니다. 즉, 특정 개체 인스턴스와 연결되지 않습니다.
  2. JVM당 하나의 인스턴스입니다.
  3. 클래스 이름을 사용하여 접근할 수 있습니다(객체가 필요하지 않음).
  4. 모든 인스턴스에 적용할 수 있는 단일 값을 포함합니다.
  5. JVM 시작 시 로드되고 JVM이 종료되면 종료됩니다.
  6. 객체의 상태를 수정하지 않습니다.

단점:

  1. 정적 멤버는 사용 여부에 관계없이 항상 메모리의 일부입니다.
  2. 정적 변수의 생성과 소멸을 제어할 수 없습니다. 유용하게도 프로그램 로드 시 생성되고 프로그램 언로드 시(또는 JVM이 종료될 때) 삭제됩니다.
  3. 동기화를 사용하여 정적 스레드를 안전하게 만들 수 있지만 추가 노력이 필요합니다.
  4. 한 스레드가 다른 스레드의 기능을 중단시킬 수 있는 정적 변수의 값을 변경하는 경우.
  5. 사용하기 전에 "정적"을 알아야 합니다.
  6. 정적 메서드를 재정의할 수 없습니다.
  7. 직렬화가 제대로 작동하지 않습니다. (직렬화란? - 객체를 저장, 전송할 수 있는 바이트 스트림으로 변환하는 것 : 직렬화에 대한 설명 )
  8. 런타임 다형성에는 참여하지 않습니다. 
  9. 많은 수의 정적 변수/메서드를 사용하는 경우 메모리 문제가 있습니다(어느 정도까지는 아니지만 그다지 많지는 않을 것 같습니다). 프로그램이 끝날 때까지 가비지 수집되지 않기 때문입니다.
  10. 정적 메서드도 테스트하기 어렵습니다.

 

정적 변수를 사용했을 시 나타나는 문제점

 

테스트 실행

정적은 일련의 단위 테스트를 함께 실행할 때(예: 지속적 통합 서버에서) 실제 문제를 일으킵니다. 한 테스트에서 다른 테스트까지 열려 있는 네트워크 소켓 개체의 정적 맵을 상상해 보세요. 첫 번째 테스트에서는 포트 8080에서 소켓을 열 수 있지만 테스트가 중단되면 맵을 지우는 것을 잊었습니다. 이제 두 번째 테스트가 시작되면 포트가 여전히 사용 중이므로 포트 8080에 대한 새 소켓을 생성하려고 하면 충돌이 발생할 가능성이 있습니다. 또한 정적 컬렉션의 소켓 참조가 제거되지 않고 (WeakHashMap을 제외하고) 가비지 수집 대상이 되지 않아 메모리 누수가 발생한다고 상상해 보세요.

이는 지나치게 일반화된 예이지만 대규모 시스템에서는 이 문제가 항상 발생합니다. 사람들은 동일한 JVM에서 소프트웨어를 반복적으로 시작하고 중지하는 단위 테스트를 생각하지 않지만 이는 소프트웨어 설계에 대한 좋은 테스트이며 고가용성을 향한 열망이 있다면 알아야 할 사항입니다.

 

미묘한 버그

스레드를 다룰 때는 정적 개체를 사용하여 데이터를 저장하는 것보다 스레드 시작 단계에서 초기화된 개체를 사용하는 것이 좋습니다. 이렇게 하면 스레드가 시작될 때마다 개체의 새 인스턴스(잠재적으로 새로운 구성 포함)가 생성되고 스레드의 한 인스턴스에서 다음 인스턴스로 데이터가 흘러나오는 것을 방지할 수 있습니다.

스레드가 종료되면 정적 개체가 재설정되거나 가비지 수집되지 않습니다. (정적 개체는 프로그램이 종료되어야 생명주기가 끝이 나기 때문에)"EmailCustomers"라는 스레드가 있고 스레드가 시작되면 이메일 주소 목록으로 정적 문자열 컬렉션을 채운 다음 각 주소에 이메일을 보내기 시작한다고 가정해 보세요. 스레드가 어떻게든 중단되거나 취소되어 고가용성 프레임워크가 스레드를 다시 시작한다고 가정해 보겠습니다. 그런 다음 스레드가 시작되면 고객 목록을 다시 로드합니다. 그러나 컬렉션은 정적이므로 이전 컬렉션의 이메일 주소 목록이 유지될 수 있습니다. 이제 일부 고객은 중복된 이메일을 받을 수 있습니다.

728x90
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/12938

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

답지 안보고 풀었을 때 쾌감이란~

모든 문제가 이렇게 잘 풀렸으면 좋겠다 

 

정말 코테는 종이 없으면 못풀겠다 

갤탭씨에게 감사인사를 드립니다. 

 


문제 풀이

 

{} 집합에 어떤 수가 올지, 몇 개가 올지는 모르지만 

 

조건 

집합 안의 수 합이 S가 되는 애들

그리고 집합 수끼리 곱한 수가 최대인 애들을 return 해라 

 

처음에는 {} 집합 안에 있는 수를 주는 줄 알았다. 

매개변수를 보니 n 집합 안의 수의 갯수, s 집합 안의 수들의 합  

이렇게 두가지만 주어졌다. 

 

집합 안의 수들의 곱이 최대인 애가 답이라서 

합해진 S를 찢어서 곱해봤다. 

 

총합S 나누기 집합갯수 를 했을 때 몫이 0보다 작거나 0이면 바로 return -1

나눴을 때 나머지 없이 몫이 떨어지면 간단! [몫, 몫, 몫] 이렇게 몫이 n개 있으면 됐다.

나머지가 있으면 나머지를 처리해야했다. 집합끼리 곱했을 때 최대가 되도록!

 

 

(처음에는 n이 2개라고 가정하고 식을 써봤다. 곱한 최대값을 어떻게 비교할지가 막막해서. 그런데 막상 보니까 나머지 없이 잘 나눠떨어지는 애들은 전부 집합이 몫으로 같음. 이걸보니 집합끼리 수 차이가 작을수록 모두 곱했을 때 결과가 크구나가 보였다. 기준을 몫으로 나눠떨어지는 애들 아닌애들로 처리해야함이 보였다.)

 

<막혔던 부분>

인덱스 초과를 자꾸 시켰다. 

문제1. answer 답 배열에 몫을 n번 저장하면 되는데  n번을 while안에서 1씩 없애주면서 n 반복해서 넣어주었다. 

넣는 값을 s//n로 해놔서 n이 값이 변경되었다.  

k =n으로 해서 k를 하나씩 빼줬다. 지금 보니 그냥 s//n 몫을 제대로 선언하는게 나을듯

 

문제2. 아직 answer 에 값 넣지도 않았는데 나머지를 처리한다고 answer[0] = 값을 할당했다. 이렇게 했다.  아직 0번째 값은 없는데.. answer은 빈 배열인데요.. 그리고 답은 (집합의 수는) 작은 수부터 정렬을 원해서 나머지를 뒤에서부터 넣어줘야했다. 

 

나머지를 1씩 쪼개서 맨뒤에서부터 하나씩 더해줬다. 

range로 범위정할 때 잘 안돼서 찾아봤다. 

my_list = [1, 2, 3, 4, 5]

for i in range(len(my_list) - 1, -1, -1):
    print(my_list[i])

시작: len(my_list_ -1)

맨 뒤!

범위: -1

맨뒤! 앞에서 조회하는 range와 마찬가지로 범위는 하나 더 한 값으로 써준다. 근데 얘는 마이너스가 붙은.. 맨뒤에서 첫번째까지 

스텝: -1

한번 작동할 때마다 인덱스를 1칸씩 이동한다. 

 

 

 

결과 

def solution(n, s):
    answer = []
    max =0
    if s//n <=0:
        return [-1]
    elif s%n ==0:
        k = n
        while(k>0):
            answer.append(s//n)
            k -= 1
    elif s%n >0:
        k = n
        while(k>0):
            answer.append(s//n)
            k-= 1
        for i in range( len(answer)-1, len(answer)-s%n-1,-1):
            answer[i] += 1
            
            
            
    return answer

 

 

앗!!

얏호~

게비스콘~~

 

시간초과돼서 찾았는데 print 있어서 그랬네 짜슥아~~!! 

 

728x90
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/178870#

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

처음에는 이중 for문으로 풀었다. 테스트 코드는 통과하였으나 

시간 초과가 났다. 

 

어떻게 애들을 더해서 k를 비교할까 고민하다가 

처음에 이중for문으로 생각한 방법은 이렇게 시작 인덱스를 줄여서 더해가다가 k 값과 비교해서 해야지~였다.

def solution(sequence, k):
    answer = []
    min_difference = float('inf')
    selected_numbers =None
    for i in range(len(sequence)):
        total_sum =0
        for j in range(i, len(sequence)):
            total_sum+= sequence[j]
            if total_sum ==k: 
                if (abs(j-i) < min_difference):
                    min_difference = abs(j-i)
                    selected_numbers = (i,j)
                    break

    return selected_numbers

 

문제는 조회하는 배열의 최대 길이가

 

5 ≤ sequence의 길이 ≤ 1,000,000

 

였기에 이중포문을 하면 이차시간으로 계산되어 제곱이 되어 초과된다. 

 

시간복잡도 참고)

출처:&nbsp;https://jeleedev.tistory.com/70

그다음에 for문을 사용하지 않고 어떻게 맨앞자리 인덱스를 줄일지 고민했다. 

여기서 오래 막혔다. 

시간초과 없애려고 이중포문 없애고 해봤는데

i부터 j까지 계속 더해지는거 i를 조작못했다.

 

2차 시도 (사실 2차는 아니긴한데..)

    index = 0
    start = 1
    
    for i in range(start, len(sequence)):
        sequence[index] += sequence[i]
        print("sequence[index]:",sequence[index])
        if i == len(sequence)-1:
            index += 1
            start +=1

    return selected_numbers

이 코드는 그저 처음부터 끝까지 더하기만 한다. 

 

 

처음에 포인터로 시작과 끝을 가리키는 방법을 쓰려했는데 for문으로 어차피 다 조회하니까 시작만 

가리키면 되겠다고 생각해서 반복문에 집착한 것이 나의 실수였다..결국 한참 헤매다가 답지를 봤다.

 

최종 코드 

def solution(sequence, k):
    answer =[]
    start = 0
    end =0
    min = 1000000000
    total = sequence[0]
    while (start <= end < len(sequence)):
        if (total == k):
        
            if min > end- start+1:
                min = end - start+1
                answer =[start, end]
            total -= sequence[start]
            start += 1
        elif (total < k):
            end+= 1
            if end< len(sequence):
                total += sequence[end]  
        elif (total > k):
            total -= sequence[start]
            start += 1
          
    return answer

1.  start end 시작과 끝 두 포인터의 관계 설정이 중요

start <= end

시작포인터와 끝포인터는 같은 곳에서 시작하고 만나서 같을 수는 있어도 넘어서는 안된다. 

나는 계속 전체 배열의 길이만 넘지 말라고 맞춰서 리스트에서 벗어나는 에러가 발생했다. 

 

2. 전체 배열의 값을 더하는 total을 어떻게 처리할지

total 정의할 때 sequence[0] 첫번째 값을 할당하고 시작하면 된다. 

total은 구하고자 하는 k값을 기준으로 나뉜다. 

 

<바로 생각하기 힘들었던 부분>

1. total == k일 때 시작과 끝 두사이 거리가 최소인 값을 찾고 나서 

배열 끝까지 다시 시작과 끝을 움직여야 하는데 

end를 움직여도 될거라 생각했다. 

그렇게 한 결과 end값이 먼저 배열범위보다 커져버려서 테스트 통과를 못했다. 

전체에서 start인덱스의 값을 빼주고 start인덱스를 옮기는 것으로 수정했다. 

 

2. while범위에서 배열의 범위만큼 돌라고 했으니 문제 없을거라 생각했지만

end를 하나씩 추가하고  그 값을 sequence의 인덱스로 넣기 위해 조건을 안 걸면 저렇게 에러가 났다. 

 

 

 

결론 반복문에 그만 집착하고 효율적인 풀이를 생각해보자

컴퓨터가 우리 뇌구조랑 비슷하겠다는 생각을 했다. 생각한게 맞을 수도 있으니 포기말고 구현해봐라

 

728x90

'코딩테스트 > 프로그래머스' 카테고리의 다른 글

프로그래머스 Lv.3 최고의 집합  (1) 2023.09.07
728x90

 

875. Koko Eating Bananas

 

Koko Eating Bananas - LeetCode

Can you solve this real interview question? Koko Eating Bananas - Koko loves to eat bananas. There are n piles of bananas, the ith pile has piles[i] bananas. The guards have gone and will come back in h hours. Koko can decide her bananas-per-hour eating sp

leetcode.com

수업 때 들은 내용 복습 겸 다시 풀었다. 

 

--

코코는 바나나 먹는 걸 좋아해요. n개의 바나나 더미가 있고, i번째 더미에는 [i]개의 바나나가 있습니다. 경비원은 떠났고 몇 시간 후에 다시 올 것입니다.

코코는 시간당 바나나 섭취 속도 k를 결정할 수 있습니다. 매 시간마다 그녀는 바나나 더미를 선택하고 그 더미에서 k개의 바나나를 먹습니다. 더미에 k개 미만의 바나나가 있으면 대신에 바나나를 모두 먹고 이 시간 동안 더 이상 바나나를 먹지 않습니다.

코코는 천천히 먹는 것을 좋아하지만 경비원이 돌아오기 전에 바나나를 모두 먹고 싶어합니다.

그녀가 h 시간 내에 모든 바나나를 먹을 수 있도록 최소 정수 k를 반환합니다.

 

--

 

 

수업때 받은 코드로 풀이

 

원숭이가 주인이 오기 전 h 시간동안 바나나를 먹으려고 한다. 

pile 바나나 더미  = [ 30, 11, 23, 4, 20] 

h = 5

 

원숭이가 5시간 내에 먹을 수 있는 최소 바나나 갯수 k 를 구해야한다. 

 

예를 들어 원숭이가 1시간에 20송이를 먹을 수 있다고 치자

30송이는 20송이 + 10송이이다. 그러면 이 원숭이는 "그녀는 바나나 더미를 선택하고 그 더미에서 k개의 바나나를 먹습니다. 더미에 k개 미만의 바나나가 있으면 대신에 바나나를 모두 먹고 이 시간 동안 더 이상 바나나를 먹지 않습니다."

이 조건에 의해 30송이를 먹는데 2시간이 걸리는 셈이다. 

 

그러면 1시간에 20송이를 먹는 원숭이는 

2시간 + 1시간 + 2시간 + 1시간 + 1시간 = 총 7시간이 걸린다. 5시간 내에 먹기 실패~!

 

이걸 바이너리 서치를 이용해 풀어보자

우리가 구해야할 k의 범위를 정하고 

중간값 m을 지정해 그 m으로 piles 안에 있는 바나나를 먹었을 때 h보다 크면 실패!

h보다 작거나 같으면 시간 안에 먹기 성공!!

 

left 1, right0 을 준 건 초기화를 위함

isEdible이 true면 그 중간값이 답이다

right로 리턴하는 까닭은  m 변수 선언이 로컬로 되어있어서. 

 

중간값을 구할 때 나는 보통 (left + right ) /2 로 구하는데 이번에 다른 방법을 알았다.

 

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        int left =1 , right =0;
     
        for (int p: piles){
            right = Math.max(right, p);
      
        }
        while(left < right){
             
            int m = left +(right -left)/2;
           
            if ( isEdible(m, piles,h)){
                right = m;
         
            } else{
                left = m + 1;
            
            }
        }
     
        return right;
    }
    private boolean isEdible(int unit, int[] piles, int h){
    
        int curHour = 0;
        for (int p: piles){
          
            curHour += p /unit + (p%unit > 0 ? 1:0);
          
            if (curHour > h){

                return false;
            }
        }
        return true;
    }
}

 

int m = left + (right - left) /2;

로 하는 이유는 오버플로우를 방지하기 위해!

만약 left와 right가 각각 int의 최대범위값을 가지고 있다면 기존 코드대로 하면 나누기 2를 하기 전에 오버플로우 현상이 발생한다. 

 

728x90

'코딩테스트 > 릿코드' 카테고리의 다른 글

1680. Concatenation Of Consecutive BinaryNumbers  (0) 2024.08.01
728x90

https://shanepark.tistory.com/400

 

[MacOS] M1 맥북 도커로 ORACLE DB 실행하기

Intro M1 맥북을 처음 구입 한 이후로 약 1년 반동안, 오라클 데이터베이스를 띄우기 위해 참 많은 노력을 했었습니다. 원래부터 Oracle이 MacOS를 정식 지원을 하지는 않았지만, 그나마 이전의 맥북에

shanepark.tistory.com

이 블로그를 보고 따라했다 정말 감사하다. 

 

나는 저번에 도커로 오라클 설치 시도를 했다가 실패했는데 

기존에 포트번호를 쓰고 있는 곳이 있는지 이런 에러가 떠서 추가적인 작업이 필요했다. 

 

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

이 밑에 1521이 이미 쓰이고 있다는 이야기도 같이 찍혔다. 

 

그래서 

 sudo lsof -i :1521

로 1521 쓰고 있는 PID 번호 확인하고 (PID 는 Process ID 의 줄임말로 운영체제에서 프로세스를 식별하기 위해 부여하는 번호를 의미)

 

kill -9 50797

없앴다.

그리고 실행되어있던 colima 를 멈추고 

colima stop

 

이미 설치해 놨던 걸 찾아서 

 

 실행되고 끝난 docker container를 포함하여 출력하는 명령문

docker ps -a

 

 

다시 실행했다. 

docker start [컨테이너 이름]

 

 

728x90
728x90

~정보를 어디에 넣고 싶은데~

헷갈렸던 변수개념을 다시 잡는데 좋았다!!

 

1. 네가지 종류의 변수는 어떻게 구분하나요?

 

변수란, 고정된 상수와 달리 변화를 줄 수 있는 값이다. 

자바에는 네 가지 변수가 있다. 

 

지역변수 local variables -> 중괄호 범위 안에서 선언된 변수로 그 범위 밖으로 나갈 수 없다. 

매개 변수 parameters -> 메소드나 생성자에게 넘겨주는 변수이다. 

인스턴스 변수 instance variables -> 끼약. 이 개념을 놓치고 있었다. 메소드 밖, 클래스 내부에 선언된 변수로 static 예약어가 붙지 않았다!!

클래스 변수 class variables -> 마찬가지로 메소드 밖, 클래스 내부에 선언된 변수이지만 static 예약어가 붙는다!!!

 

 

생명 주기는 

 

지역변수 local variables -> 선언된 중괄호 내에서만 유효!

매개 변수 parameters -> 메소드 호출될 때만!

인스턴스 변수(또는 멤버 변수) instance variables -> 객체가 생성될 때 생명이 시작되고, 그 객체를 참조하고 있는 다른 객체가 없으면 소멸된다.

클래스 변수(또는 정적 변수) class variables -> 객체가 생성될 때 생명이 시작되고, 자바 프로그램이 끝날 때 소멸된다. ( 아 그래서 static 사용을 남발해서는 안되는구나. 관리가 어려워지겠구만~~ )

 

+ 자바에는 가비지 콜렉터가 있어서 얘가 알아서 메모리에서 사용하지 않는 변수를 없애준다고 한다. 

 

2.변수 이름 지을 때 대문자로 시작해도 되나요?

되지 않나? 상수값을 담는 변수를 만들때 모두 대문자..

아니면 보통 소문자로 시작!

 

3. 자료형에는 기본 자료형과 어떤 자료형이 있나요?

 

크게 보면 자바에는 

기본 자료형 Primitive Data Type , 참조 자료형 Reference Data Type 두가지가 있다. 

 

참조 자료형에서는 String을 제외하고 클래스로 객체를 생성하고 초기화할 때 new 연산자를 필수로 사용해야한다. 

String bookName = new String("Basic Java"); 물론 클래스도 다음과 같이 정의해도 상관없다. 

 

4. 기본 자료형에는 몇 가지가 있나여?

 

기본 자료형은 8개다. -> 책에서 8개에 대한 드립이 나오는데 저자의 잔잔개그가 마음에 든다.ㅋㅋㅋㅋ

 

기본 자료형은 크게 

숫자, boolean 타입으로 나뉜다. 

숫자는 다시 

정수형, 소수형으로 나뉜다. 

 

정수형: byte short int long char

소수형 float Double

기타: boolean

 

char을 제외하고 해당 타입의 변수가 정해지니 "비실한 FD" "bsil FD" 로 외우라고 한다ㅋㅋㅋㅋ감사합니당...아주 잘외워집니다!!ㅋㅋㅋ

 

6. byte는 몇 비트(bit)로 되어 있나요? 

byte는 8비트의 부호가 있는 타입이다. 

 

7. byte는 왜 만들었을까요?

적은 공간에 보다 많은 내용을 저장하기 위해서! 

일번적으로 데이터 저장 목적이 아닌 계산 시에는 int나 long을 쓴다. 

그 이유는!

byte의 최대값 127

최소값 -128인데 

 

최대값에 127 에 1을 더하면 -128이 되고 

최소값에 -128dp 1을 빼면 127이 된다. 그 이유는 오버플로우 때문!

그래서 계산의 안전성 고려한 결과이다. 

 

오버플로우란? 

: 표현가능한 범위를 벗어난 값을 말하며 돌림판처럼 돌아가는 현상을 말한다. 

컴퓨터는 값을 처리해야하는데 범위에서 벗어났으니 돌아가서 다시 시작하는 것이다. 

 

그리고 컴퓨터는 0과 1로 표현하는 2진법을 따른다. 그래서 모든 자바의 숫자 타입은 2의 배수로 그 범위가 그려진다. 

Type        Bits      Range of Values
----------------------------------------------------------------------------------------
byte         8bits    -2^7 ~ 2^7-1 (-128 ~ 127)
short       16bits    -2^15 ~ 2^15-1 (-32768 ~ 32767)
int         32bits    -2^31 ~ 2^31-1 (-2147483648 ~ 2147483647)
long        64bits    -2^63 ~ 2^63-1 (-9223372036854775808 ~ 9223372036854775807)
float       32bits    0x0.000002P-126f ~ 0x1.fffffeP+127f
double      64bits    0x0.0000000000001P-1022 ~ 0x1.fffffffffffffP+1023  
char        16bits    \u0000 ~ \uffff (0 ~ 2^15-1) * 자바에서 unsgined로 동작하는 자료형 (0 ~ 65,535)
boolean      1bit     true, false

참고 : https://jdm.kr/blog/213

8. int와 long 중 어떤 타입이 더 큰 숫자를 처리할 수 있나요?

long

9. 소수점을 처리하는 타입은?

float, double 이 있다. 

이 둘은 32비트와 64비트로 제공할 수 있는 범위를 넘어서면 그 값의 정확성을 보장못해서 중요한 계산을 할 때는 써서는 안된다. 

java.math.BigDecimal이라는 클래스를 하용하면 정확한 계산을 할 수 있다. 

소수점 처리시 보통 double을 많이 사용한다. 

 

10. char은 정수형인가요?

 

char는 8비트 정수형 처리 변수로 character(문자)의 약자이다. 

그런데 문자열과 관련된 부분에서 사용된다. 

11.  a라는 것을 char로 정의할 때 어떤 기호로 감싸주어야하나요?

''

12. true 와 false 두개의 값만 가지는 타입은 ?

boolean

 

 

728x90
728x90
메소드를 부르기 전에 객체 생성해야 한다ㅏ. 

public static void main(String[] args){

System.out.println("계산기 클래스 시작");
//클래스!!  //객체이름         //생성자!
Calculator calc = new Calculator();



}

-생성자를 이용해서 객체를 만든다. 기본 생성자는 만들지 않아도 자동으로 생성해준다!-

 

 

public class Profile {
	String name;
	int age;
	
	public void setName(String str) {
		this.name = str; //결과 같다.
//		name = str; 
		
	}
	public void setAge(int val) {
		age = val;
	}
	public void printName() {
		System.out.println(name);
		
	}
    }

this연산자를 꼭 붙여야되는 줄 알았는데 아니었구나.

 

-this 연산자 필수야? 에 대한 답변 -

this연산자는 클래스 내 현재 객체를 참조하기 위한 키워드로 사용된다.

사용하지 않아도 클래스의 멤버 변수와 메서드를 참조할 수 있다.

다만 다음과 같은 경우를 위해 쓰자. 

 

package chapter03;

public class Profile {
	String name;
	int age;
	
	public void setName(String str) {
		this.name = str;

		
	}

	
	public void printName(String name) {
        System.out.println("Local variable name: " + name);
        System.out.println("Member variable name: " + this.name); // this 키워드 사용
    }


	public static void main(String[] args) {

		Profile profile = new Profile();
		String name = "Min";

		profile.setName(name);

		profile.printName("?????");
		
		

	}

}

인자값으로 받은 로컬변수를 그대로 넘겨주고 

두번째 this.name으로는 클래스의 변수값을 가져오고 있다. 

 

 

 

-클래스와 객체 구분해라~

 

??: 객체와 인스턴스 가 더 헷갈려요

 

책에서 명확한 답을 주지 않고 표현하고 있어서 개념을 더 찾아봤다.

 

클래스: 대명사 , 객체를 만들기 위한 템플릿,설계도 역할을 한다.  비슷한 동작을 가지는 객체들을 쉽게 관리할 수 있다!  ex) 자동차,,핸드폰,,

?: 정말 추상적인데요? / 네 추상화된 개념입니다. 

 

클래스에는 변수들과 메소드가 담겨있다.

 

객체클래스 타입으로 선언되었을 때를 의미한다.   ex) 자동차 아이폰 = new 자동차();   -> 아이폰 객체

 

그럼 인스턴스는?

객체가 실제 메모리에 할당되어 사용될 때 인스턴스라고 한다. 

(클래스의 인스턴스화 -> 는 클래스로 객체를 생성한 것을 의미, 실제로 구현한다는 뜻) 

 

 

"인스턴스는 일반적으로 실행중인 임의의 프로세스, 클래스의 현재 생성된 오브젝트(객체)를 가리킨다. 

객체의 인스턴스는 데이터베이스나 백그라운드 프로세스 등 광범위한 컴퓨터 시스템 자원의 접근에 할당된 물리 메모리의 일부를 가리킨다. "

"인스턴스는 객체에 포함된다 볼 수 있다. 객체 지향 언어에서의 관점은 객체가 메모리에 할당되어 실제 사용될 때 인스턴스라고 부른다. 추상적인 개념과 구체적인 객체 사이 관계에 초점을 맞출 경우에 사용된다. 객체는 클래스의 인스턴스이고, 객체 간의 링크는 클래스 간의 연관 관계의 인스턴스이며, 실행 프로세스는 프로그램의 인스턴스이다. 즉, 인스턴스라는 용어는 반드시 클래스와 객체 사이의 관계로 한정지어서 사용할 필요는 없으며, 어떤 원본으로부터 생성된 복제본을 의미한다"

 

 

 

참고

http://wiki.hash.kr/index.php/%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4

https://cooablue.tistory.com/entry/%EA%B0%9D%EC%B2%B4Object%EC%99%80-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4Instance

 

 

 

정리해봅시다 문제

 

1. 클래스와 객체의 차이점

클래스는 껍데기에 불과. 클래스를 통해 객체를 생성해서 객체의 메소드와 변수를 가져와 사용한다. 

 

2. 객체를 생성하기 위해서 꼭 사용해야하는 예약어는?

new 연산자~

 

3. 객체를 생성하기 위해서 사용하는 메소드 같이 생긴 클래스 이름에 소괄호가 있는 것은 뭐냐?

생성자요

4. 객체의 메소드를 사용하려면 어떤 기호를 객체 이름과 메소드 이름 사이에 넣어주어야하나요?

.

5. 클래스의 일반 메소드를 사용하기 위해서 어떤 것들을 만들어야하나요?

 

객체를 생성해야한다. 

728x90
728x90

1장 

 

1. 클래스란 무엇인가?

클래스는 자바의 가장 작은 단위이다. ( 클래스가 객체를 만들어주는 설계도다~라고만 이해하고 있었는데

자바는 객체 세상이구나~를 깨달으니까 이해가된다. 모든 것이 객체인 자바.)

클래스는 상태와 행동을 가지고 있다. (반드시 가져야되는건 아니다.) 상태는 필드, 행동은 메소드로 나타낸다.  

 

2. 메소드가 무엇인가?

메소드란 클래스 안에 위치한 특정 부분 코드 실행해주는 블록

메소드는 이름을 가지고 리턴값에 따른 리턴타입을 가진다. 

 

3. 메소드의 매개변수는 어디에 적어주나?

public void add (int value){

}

여기서 value값이 매개변수이다. 정의한 메소드 이름 옆에 적는다. 

4. 메소드 이름 앞에 꼭 적어 줘야하는 것은?

접근 제한자 , 리턴타입, 이다. 

6. 메소드에서 결과를 돌려주려면?

return 예약어를 쓰면 된다. 

 

예약어란 말그대로 예약된 이름이라 변수이름으로 사용할 수 없는 이름들을 말한다. 

예약어는 클래스, 변수이름, 메소드명으로 쓸 수 없다. 

 

2장 

 main() 메소드의 메소드 이름 앞에는 어떤 예약어들이 들어 가나요?

접근제어자 public, 정적 static , 리턴타입 void

 

 

메소드를 선언할 때 반드시 꼭 있어야 하는 세가지는 무엇인가요?

리턴타입 메소드 이름 메소드 내용 

728x90
728x90

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

 

1463번: 1로 만들기

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

www.acmicpc.net

나만 어려운 문제일 수 있다 ㅎㅎ

피보나치문제는 되게 간단하던데 이 문제는 답지를 봐도 이해가 안되어서 하나하나 적으면서 풀어봤다.

 

이해가 안갔던 이유:

계산한 값들을 배열에 저장해야된다고 생각했다. 

숫자가 인덱스라는 점이 안 와 닿았다. 

 

코드 보면서 얘기해보자~~

 

먼저 dp 다이나믹 프로그래밍은

반복적인 계산을 효율적으로 처리를 하는 알고리즘이다. 

큰문제를 작은 문제로 나누어 해결하고 그 결과를 저장해놨다가 재사용하여 중복계산을 피한다.

 

피보나치 보면 이해가 바로 가능하다

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

n = int(input())
#앞서 계산된 결과를 저장하기 위한 DP테이블 초기화
#n번째
d = [0]* (n+1)
print("d:",d)
#피보나치 수 : 0, 1, 1, 2, 3, 5....
#0,1로 시작하는 값
#인덱스 1번째 1  
d[1] =1
#반복문은 2번째부터 시작. 
for i in range(2, n+1): #2~n까지
	#1= 1+0
    d[i] = d[i-1]+ d[i-2]
    print(d[n])

 

처음 0,1을 주고 시작함!

그러면 인덱스 2, 부터 계산됨

 

 

그렇다면 이 문제.

 

 

피보나치는 더한 값들을 배열 d에 기록해서 간단했는데

이문제는 구하고자 하는 값이 횟수이다. 횟수를 기록해야한다.

 

숫자 10이 몇 번의 횟수를 거쳐 1이 되었냐~ 는 문제이다.

이 숫자 10과 횟수의 관계를 코드로 정립 못했었다..

횟수를 기록한 d배열의 인덱스가  "주어진 숫자" 역할을 했다. 그게 잘 안와닿았다.

 

즉 인덱스 3은 숫자 3. 그러면 인덱스 3에 횟수를 기록하게 되는 것이다. 

 

횟수를 기준으로 하니, 현재 횟수가 이전횟수 + 1이다라는게 겨우 이해되었다.

 

숫자가 2나 3으로 나눠지는 경우 : 예) 숫자가 6이면 "이전5의 횟수+ 1"을 하면 4가 되는데, 숫자 6은 2로 나눠지기때문에
최솟값으로 비교를 한다. "이전5의 횟수+ 1"  과 "d[6//3] 즉 d[2] 숫자2의 횟수에 1을 더한 값"을 비교하는 것이다.

나는 하나하나 값 넣어서 적어보면서 이해했다 ㅎㅎㅎ

# 답지
# n = int(input())
n = 10
print('n',n)
 
#계산한 횟수를 저장하는 용이래!!!
d = [0] * (n+1) 
print("d",d)

for i in range(2, n+1):  #2부터하는이유는0,1은 나누어떨어지지 않아서 횟수가 걍 0이라서!
    d[i] = d[i-1] +1 #더하기 1을 하는 이유는 기존횟수느 = 이전 횟수에 + 1 식 늘어나니까. 
   #i가 3으로 나눠지는 값이면 
    if i %3 == 0:
        #숫자 3의 횟수는 = 이전 횟수에 하나더한 횟수거나, 3으로 나눈 값의 횟수에 하나 더한 횟수! 둘중에 더 작은 값!
        d[i] = min(d[i], d[i//3]+1)
        print("3d[i]:", d[i])
    if i%2 == 0:
        d[i] = min(d[i], d[i//2]+1)

 
print(d[n])

 

 

 

 

728x90
728x90

다른 분들의 코드를 찾아보면서도 이해가 안되었는데 역시 직접 찍어가면서 하는게 제일 빠르다. 

물론 나는 답지를 보면서 ㅎㅎ

 

문제 이해를 잘못해서 엄청 헤멨다.

Magic square 마방진

 

마방진이란?

가로의 숫자들 더한 값,

세로의 숫자들 더한 값,

대각선숫자들 더한 값이 모두 같은 사각형!

 

문제가 요구하는 바:

https://www.hackerrank.com/challenges/magic-square-forming/problem?isFullScreen=true 

 

Forming a Magic Square | HackerRank

Find the minimum cost of converting a 3 by 3 matrix into a magic square.

www.hackerrank.com

input값으로 만든 행렬을 마방진으로 만들어서 두 행렬을 비교하고

바뀐 값들의 차 중에 가장 작은 수들를 더해서 출력!

 

1. 먼저 주어진 값을 마방진으로 만들어야 한다!

근데 우리는 가장 작은 수들을 찾기를 윈해서 모든 경우의 마방진을 만들어봐야했다.

 

여기서 배운 파이썬 함수

permutations

순열을 만들어주는 함수다. 

(순열이란, 조합과 달리 순서를 고려해 나열한 경우의 수를 말한다)

 

먼저 인풋 값 자체를 코드로 체크할 수 있게 정리해줬다 

이 인풋값을 차례로 넣어줬다. 

그결과 X = [5,3,4,1,5,8,6,4,2]가 되었다. 

지금은 이것은 마방진이 아니다. 

마방진으로 만들기 위해 모든 순서의 경우의 수를 만들어보자. 

1부터 9까지! 

for문 안에 P를 찍어보면 엄청많다

등등..

여기서 마방진 조건에 맞는 애들을 찾아주자. 

가로끼리 더한 값이 15

세로끼리 더한 값이 15

대각선끼리 더한 값이 15

 

파이썬 코드에 익숙하지 않아서 이 조건을 이해하는데 좀 걸렸다. 

p(0:3) 은  인덱스0,1,2라는 뜻이다. 위 인풋모양 생각하면 맨 위의 가로 한면! 여기 sum() 이 감싸니까 즉, (8 +3+4)

p(3:6)은  인덱스 3,4,5 맨 오른쪽 세로 한면 (4+9+2)

p(0::3) 이건 p배열에서 p[0]에서 시작해서 세칸씩 이동한 값  p = [8,3,4,1,5,9,6,7,2 ] 이므로 (8+1+6)

p(1::3) 얘도 같음 (3+5+7)

대각선도 다 더해서 15여야함

P[0] + P[4] + P[8] == 15 

P[2] + P[4] + P[6] == 15)

P[-3::] 이건 뒤에서 3번째에서 끝까지 더한 값 (6+7+2)

 

 

 

 

 

이렇게 마방진 조건을 다 갖춘P와 기존인풋이었던 X의 차

둘이 그냥 빼는게 아니라 모든 인덱스의 값들을 비교해서 빼야해서 

range(0,9)  for문으로 0부터 8인덱스까지 비교해서 빼줌

abs() 로 감싼이유는 만약에 2-3 나오면 음수니까 양수로 만들어주려고 씀. 

그 차리르 다 더한 값 중에 가장 작은  값으로~ min()

 

"Ans가 또 들어가는 이유는 for 루프를 통해 permutations의 모든 경우를 탐색하면서 최소값을 찾기 위해서입니다.

for 루프는 permutations(range(1,10))를 통해 1부터 9까지의 숫자로 이루어진 순열을 하나씩 가져옵니다. 각 순열을 P로 표현하고, 조건문을 통해 해당 순열이 마방진(magic square)의 조건을 만족하는지 확인합니다.

만약 조건을 만족하는 마방진이라면, sum(abs(P[i] - X[i]) for i in range(0,9))를 통해 해당 마방진과 주어진 X 리스트와의 차이의 합을 계산합니다. 그리고 이 값을 기존의 Ans와 비교하여 작은 값으로 Ans를 갱신합니다.

따라서, for 루프를 통해 모든 경우를 탐색하면서 찾은 최소 차이의 합을 Ans에 저장하게 됩니다."

 

 

from itertools import *

X = []
X.extend(list(map(int,input().split())))
X.extend(list(map(int,input().split())))
X.extend(list(map(int,input().split())))

Ans = 81
for P in permutations(range(1,10)):
   
    if sum(P[0:3]) == 15 and sum(P[3:6]) == 15 and sum(P[0::3]) == 15 and sum(P[1::3]) == 15 and P[0] + P[4] + P[8] == 15 and (P[2] + P[4] + P[6] == 15) and  sum(P[-3::]) == 15:
        # print("PPPP:",P) #P is magic square
        Ans = min(Ans, sum(abs(P[i] - X[i]) for i in range(0,9)))
print(Ans)
728x90
728x90
import sys
sys.stdin = open('1920.txt','r')
input = sys.stdin.readline
N = int(input())
A = list(map(int, input().split()))
M = int(input())
array = list(map(int, input().split()))

A.sort()
for num in array:

    lft, rt = 0, N-1
    isExist = False
    while lft <= rt:
        mid = ( lft+ rt ) //2
        if num == A[mid]:
            print(1)
            isExist =True
            break
        elif num < A[mid]:
            rt = mid -1 
        elif num >A[mid]:
            lft = mid +1
        
    if not isExist:
        print(0)

변수를 정하고 하는 것부터 적응이 안되었음

 

입력값 변수로 만들어 놓고

출력값 똑같이 나오도록 짜야하는데

 

문제 보고 이진탐색으로 하면 되겠다!

는 알았는데 

" 이 수들이 A안에 존재하는지 알아내면 된다. "

이부분이 이해가 안갔었다.

 

 

5
4 1 5 2 3
5
1 3 7 9 5

A리스트를 정렬해서 순서대로 해놓고

거기서 array의 값들을 하나하나 찾아보는 방식!

A안에 존재하면 1

없으면 0

 

이진탐색 방법으로 할것이고 

array전체를 돌기때문에 for문

 

 

https://velog.io/@deannn/BOJ-%EB%B0%B1%EC%A4%80-1920%EB%B2%88-%EC%88%98-%EC%B0%BE%EA%B8%B0-Python

 

----

 

참고

c = '1,2'

# print(list(map(int, c.split(',')))) #split은 문자열에만 된다. 배열을 하고 싶으면 join

#결과

[1,2] 

 

 

728x90

+ Recent posts