728x90
반응형

📝 문제

더보기

1. 문제 설명

코딩테스트를 준비하는 머쓱이는 프로그래머스에서 문제를 풀고 나중에 다시 코드를 보면서 공부하려고 작성한 코드를 컴퓨터 바탕화면에 아무 위치에나 저장해 둡니다. 저장한 코드가 많아지면서 머쓱이는 본인의 컴퓨터 바탕화면이 너무 지저분하다고 생각했습니다. 프로그래머스에서 작성했던 코드는 그 문제에 가서 다시 볼 수 있기 때문에 저장해 둔 파일들을 전부 삭제하기로 했습니다.

컴퓨터 바탕화면은 각 칸이 정사각형인 격자판입니다. 이때 컴퓨터 바탕화면의 상태를 나타낸 문자열 배열 wallpaper가 주어집니다. 파일들은 바탕화면의 격자칸에 위치하고 바탕화면의 격자점들은 바탕화면의 가장 왼쪽 위를 (0, 0)으로 시작해 (세로 좌표, 가로 좌표)로 표현합니다. 빈칸은 ".", 파일이 있는 칸은 "#"의 값을 가집니다. 드래그를 하면 파일들을 선택할 수 있고, 선택된 파일들을 삭제할 수 있습니다. 머쓱이는 최소한의 이동거리를 갖는 한 번의 드래그로 모든 파일을 선택해서 한 번에 지우려고 하며 드래그로 파일들을 선택하는 방법은 다음과 같습니다.

  • 드래그는 바탕화면의 격자점 S(lux, luy)를 마우스 왼쪽 버튼으로 클릭한 상태로 격자점 E(rdxrdy)로 이동한 뒤 마우스 왼쪽 버튼을 떼는 행동입니다. 이때, "점 S에서 점 E로 드래그한다"고 표현하고 점 S와 점 E를 각각 드래그의 시작점, 끝점이라고 표현합니다.
  • 점 S(luxluy)에서 점 E(rdxrdy)로 드래그를 할 때, "드래그 한 거리"는 |rdx lux| + |rdy luy|로 정의합니다.
  • 점 S에서 점 E로 드래그를 하면 바탕화면에서 두 격자점을 각각 왼쪽 위, 오른쪽 아래로 하는 직사각형 내부에 있는 모든 파일이 선택됩니다.

예를 들어 wallpaper = [".#...", "..#..", "...#."]인 바탕화면을 그림으로 나타내면 다음과 같습니다

이러한 바탕화면에서 다음 그림과 같이 S(0, 1)에서 E(3, 4)로 드래그하면 세 개의 파일이 모두 선택되므로 드래그 한 거리 (3 - 0) + (4 - 1) = 6을 최솟값으로 모든 파일을 선택 가능합니다.

(0, 0)에서 (3, 5)로 드래그해도 모든 파일을 선택할 수 있지만 이때 드래그 한 거리는 (3 - 0) + (5 - 0) = 8이고 이전의 방법보다 거리가 늘어납니다.

 

머쓱이의 컴퓨터 바탕화면의 상태를 나타내는 문자열 배열 wallpaper가 매개변수로 주어질 때 바탕화면의 파일들을 한 번에 삭제하기 위해 최소한의 이동거리를 갖는 드래그의 시작점과 끝점을 담은 정수 배열을 return하는 solution 함수를 작성해 주세요. 드래그의 시작점이 (lux, luy), 끝점이 (rdx, rdy)라면 정수 배열 [lux, luy, rdx, rdy]를 return하면 됩니다.


2. 제한사항

  • 1 ≤ wallpaper의 길이 ≤ 50
  • 1 ≤ wallpaper[i]의 길이 ≤ 50
    wallpaper의 모든 원소의 길이는 동일합니다.
  • wallpaper[i][j]는 바탕화면에서 i + 1행 j + 1열에 해당하는 칸의 상태를 나타냅니다.
  • wallpaper[i][j]는 "#" 또는 "."의 값만 가집니다.
  • 바탕화면에는 적어도 하나의 파일이 있습니다.
  • 드래그 시작점 (luxluy)와 끝점 (rdxrdy)는 lux rdxluy rdy를 만족해야 합니다.

3. 입출력 예

wallpaper result
[".#...", "..#..", "...#."] [0, 1, 3, 4]
["..........", ".....#....", "......##..", "...##.....", "....#....."] [1, 3, 5, 8]
[".##...##.", "#..#.#..#", "#...#...#", ".#.....#.", "..#...#..", "...#.#...", "....#...."] [0, 0, 7, 9]
["..", "#."] [1, 0, 2, 1]

 

4. 입출력 예

  • 입출력 예 #1
     문제 설명의 예시와 같은 예제입니다. (0, 1)에서 (3, 4)로 드래그 하면 모든 파일을 선택할 수 있고 드래그 한 거리는 6이었고, 6보다 적은 거리로 모든 파일을 선택하는 방법은 없습니다. 따라서 [0, 1, 3, 4]를 return합니다.

  • 입출력 예 #2
     예제 2번의 바탕화면은 다음과 같습니다.(1, 3)에서 (5, 8)로 드래그하면 모든 파일을 선택할 수 있고 이보다 적은 이동거리로 모든 파일을 선택하는 방법은 없습니다. 따라서 가장 적은 이동의 드래그로 모든 파일을 선택하는 방법인 [1, 3, 5, 8]을 return합니다.

 

  • 입출력 예 #3
     예제 3번의 바탕화면은 다음과 같습니다.모든 파일을 선택하기 위해선 바탕화면의 가장 왼쪽 위 (0, 0)에서 가장 오른쪽 아래 (7, 9)로 드래그 해야만 합니다. 따라서 [0, 0, 7, 9]를 return합니다.

 

  • 입출력 예 #4
     예제 4번의 바탕화면은 다음과 같이 2행 1열에만 아이콘이 있습니다.이를 드래그로 선택하기 위해서는 그 칸의 왼쪽 위 (1, 0)에서 오른쪽 아래 (2, 1)로 드래그 하면 됩니다. (1, 0)에서 (2, 2)로 드래그 해도 아이콘을 선택할 수 있지만 이전보다 이동거리가 늘어납니다. 따라서 [1, 0, 2, 1]을 return합니다.

✏️작성한 코드

코드 풀이를 해보자.

일단 X, Y를 행과 열로 생각한다.

  •  int[] X = new int[wallpaper.length]; 
    wallpaper 배열에 들어가 있는 값의 길이 만큼 X, Y도 출력되서 나오므로 X, Y를 wallpaper 만큼의 길이를 가진 리스트로 설정했다.
  • int xMin = Integer.MAX_VALUE;
    X, Y에 들어간 값 중 행의 최솟값과 행의 최댓값, 열의 최솟값과 열의 최댓값을 찾아야 하므로 각각을 변수로 설정한다.  Integer.MAX_VALUE는 JAVA에서의 정수 최댓값을 의미하기 때문에 최솟값을 구하려고 할 때 MAX_VALUE와 비교해야 한다.

  • for 문
    중첩된 루프를 사용하여 wallpaper 배열을 순회하면서 '#' 문자를 찾고, 해당 위치의 행과 열을 XY 배열에 저장하고 최솟값과 최댓값을 업데이트합니다.

  •  Math.min(A, X[i])
    Math.min(a, b)은 두 인자 값 중 작은 값을 리턴한다. 즉, A가 Integer.MAX_VALUE 이므로 X[i]이 그보다 더 클 수 없다. 그러므로 처음 들어오는 X[i]의 값이 A로 리턴되면서 새로 들어오는 X[i]과 비교하여 최소값을 반환하게 된다.

  • xMax = Math.max(C, X[i]+1);
    Max 값에 1을 더해준 이유는 파일이 교차되는 점에 위치해 있는게 아닌 한 개의 구역을 차지하고 있기 때문에 드래그 했을 때 마지막 위치가 구역의 시작이 아닌 마지막이므로 1을 더 해줘야 해야 한다.
class Solution {
    public int[] solution(String[] wallpaper) {
        int[] X = new int[wallpaper.length]; 
        int[] Y = new int[wallpaper.length];

        int xMin = Integer.MAX_VALUE;
        int yMin = Integer.MAX_VALUE;
        int xMax = Integer.MIN_VALUE;
        int yMax = Integer.MIN_VALUE;

        for (int i = 0; i < wallpaper.length; i++) {
            for (int j = 0; j < wallpaper[i].length(); j++) {
                if (wallpaper[i].charAt(j) == '#') {
                    X[i] = i;
                    Y[i] = j;

                    xMin = Math.min(A, X[i]);
                    yMin = Math.min(B, Y[i]);
                    xMax = Math.max(C, X[i]+1);
                   	yMax = Math.max(D, Y[i]+1);
                }
            }
        }

        int[] answer = {xMin, yMin, xMax, yMax};
        return answer;
    }
}

 
728x90
반응형
728x90
반응형

데이터 설계하기


🫐 테이블 설계하기

  • 테이블명, 컬럼명, 컬럼타입, null 여부에 대한 정의가 필요함
  • 산출물
    - 테이블 정의서
    - ERD
    - 스크립트 명세서

🫐 테이블 정의서

  • 자료형 길이 설정 시 한글은 *2
  • double
    소숫점을 가지는 많은 양의 데이터
    정밀도를 요구하는 데이터
    소숫점 아래 값이 많은 데이터

 

🫐 스크립트 명세서

  • SQL에 그대로 작성하여 테이블 생성

Create Table time_power_demand(
	ymd varchar(10) NOT NULL,
   time varchar(4) NOT NULL,
	power DOUBLE NOT null
);

 

DB 연결하기

🫐 데이터 저장시에 유용한 라이브러리

  • sqlalchemy
  • 설치 : pip install sqlalchemy

🫐  데이터 저장시에 유용한 라이브러리

  • pymysql
  • 설치 : conda install -c conda-forge pymysql
  • 설치 : pip install pymysql

🫐 Database 연결하기

from sqlalchemy import create_engine

### 연결정보 작성
db_connection_info = "mysql+pymysql://gjuser:dbdb@localhost:3306/gjdb"

### Database 연결하기
db_connection = create_engine(db_connection_info)
db_connection

데이터 프레임을 Table에 저장시키기

🫐 컬럼명 수정

  • 데이터프레임의 컬럼명을 테이블의 컬럼명과 같게 수정
  • 특정 컬럼명만 수정하고자 할 때
    → df.columns = [{"년도" : "ymd"}]
# - 데이터프레임의 컬럼명 전체수정하기
df.columns = ["ymd", "time", "power"]
df


🫐 데이터 저장하기

df.to_sql(name="time_power_demand",
         con=db_connection,
         index=False,
         if_exists="append")

 

8760 rows 저장 완료

 

 

 

SQL 조회시 값이 들어가 있는 것을 확인할 수 있다.

 

 

 

 

 

 

 

 

 

 

 


🫐 데이터베이스 자원 반환(접속 끊기)

  • 연결 종료하기
db_connection.dispose()

데이터 조회하기

🫐 데이터 조회

  • 조회시에는 pymysql 라이브러리 사용

🫐데이터베이스 연결

import pymysql
### 접속 정보
# - 접속 허가를 위한 정보
# - 접속 id or 도메인
host = "localhost"
# - 사용자계정
user = "gjuser"
# - 패스워드
password = "dbdb"
# - 데이터베이스명
db = "gjdb"
# - 한글처리
charset = "utf8"
# - 조회시 컬럼명을 동시에 보여줄지 여부 설정
cursorclass = pymysql.cursors.DictCursor

 

🫐 DB 접속하기

  • connect로 서버에 연결 허가를 요청하여 conn에 허가를 받음
try :
    conn = pymysql.connect(host = host,
                           user = user,
                           password = password,
                           db = db,
                           charset = charset,
                           # autocommit = autocommit,
                           cursorclass = cursorclass)
    print("DB접속 성공 >>> ", conn)
except :
    print("DB Server Checking...")

 

🫐 커서 받아오기

cur = conn.cursor()
cur

 

🫐 Select 문 생성 후 DB에게 요청 및 응답 받기

  • execute가 "Select * from time_power_demand"라는 요청문을 서버에게 가지고 가서 그에 대한 답을 가져 
sql = "Select * from time_power_demand"
rs_cnt = cur.execute(sql)
print(f"{rs_cnt}건이 조회 되었습니다.")

 

🫐 커서 및 커넥션 정보 반납(종료)하기

try:
    cur.close()
    conn.close()
except :
    print("이미 모든 커서와 접속 정보가 반납되었습니다.")
728x90
반응형
728x90
반응형

데이터 수집하기


🫐 한국전력거래소 시간별 전력수요량 데이터 수

  • 수집위치 : data.go.kr
  • 한국전력거래소 시간별 전력수요량 csv 파일 다운로드

 

데이터 불러들이기

🫐 데이터 프레임 변수명 : df

  • df = pd.read_csv(file_path)
    → 이렇게 작성하면 UnicodeDecodeError 에러
    → 인코딩 필요
  • pandas는 기본적으로 utf-8
  • 메모장 저장될 때 기본 utf-8, 공공데이터 저장 ansi
  • euc-kr 한국어 타입으로 인코딩
import pandas as pd
file_path = "./01_data/한국전력거래소_시간별 전력수요량_20211231.csv"
df = pd.read_csv(file_path, encoding= "euc-kr")
df

 

🫐 결측데이터 확인

df.info()

 

- 결측치는 없다

 

 

 

 

 

 

 

 

 

 

 

 

 

🫐 이상치 데이터 확인
- 측정된 데이터 이므로 min을 보는게 적절하다
- min이 0 이하로 떨어지면 이상치

df.describe()


🫐 컬럼명의 시간을 데이터화 하기 위하여 컬럼명 추출하기

df.columns

 

🫐 변수로 받기

col_list = df.columns
col_list

 

데이터 프레임 생성하기

 

🫐 3개의 열 (년도, 시간, 전력량)을 가지는 데이터프레임 생성하기

result_df = pd.DataFrame(columns=["년도", "시간", "전력량"])
result_df


🫐데이터프레임에 데이터 행단위 추가하기

  • items() : 튜플로 만들어서 넘겨주면 그 안에 갯수만큼 왼쪽의 변수들이 각각 받아준다.
  • print(ymd, "/", time, "/", value) : 2021-12-31 / 24시 / 70123 까지 추출된다.
  • concat() : 데이터프레임과 데이터프레임을 행단위(axis = 0) 또는 칼럼단위(axis = 1)로 추가할 때 사용
  • ignore_index=True : 행이 추가될 때 행 인덱스 번호를 자동증가 시키기 (default = false)
### 데이터프레임에 데이터 행단위 추가하기
result_df = pd.DataFrame(columns=["년도", "시간", "전력량"])

for index, row in df.iterrows() :
    # print(row)
    ### 년도 데이터
    ymd = row[col_list[0]] # 날짜
    
    ### 시간과 전령량이 합쳐진 데이터
    data = row[col_list[1:]] # 1시 부터 24시 까지. 모든 시간대
    # print(data)

    ### 시간과 전력량을 각각 추출하여 데이터프레임에 넣기
    # - 넣을 값 : 날짜, 시간, 잔력량
    for time, value in data.items() :
        # print(ymd, "/", time, "/", value)

        ### 행단위로 데이터프레임에 추가하기 위해서 추가할 행을 데이터프레임으로 생성
        df_temp = pd.DataFrame({"년도":[ymd], "시간":[time], "전력량":[value]})

        ### 데이터프레임에 행단위로 추가하기
        result_df = pd.concat([result_df, df_temp], axis=0, ignore_index=True)
        
### 최종결과 출력
result_df


       

🫐 정제된 데이터 파일로 저장하기

  • 저장할 경로 지정
  • index=False : 인덱스 번호값은 저장하지 않기(default = True)
save_path = "./01_data/new_data.csv"
result_df.to_csv(save_path, index = False)

좌) index = True 우) index = False 

🫐 저장한 데이터 파일 읽어들이기

file_path = "./01_data/new_data.csv"
df = pd.read_csv(file_path)
df

728x90
반응형
728x90
반응형

판다스(Pandas)

 

    • 행렬 데이터를 처리하기 위한 다양한 함수를 지원하는 라이브러리
    • 파일 읽기, 저장, 행렬데이터 처리, 기본 시각화 등 지원
    • 데이터 전처리 과정에서 주로 사용됨

데이터 분석과정

 

  • 데이터 수집 > 데이터 전처리 > 데이터 가공(필요시 전처리) > 데이터 분석 탐색/시각화(필요시 전처리) > 필요시 모델 훈련(머신러닝 or 딥러닝) > 웹서비스 또는 분석 보고서
  • 책에 나온 일반적인 과정 : 데이터수집 > 전처리 > 분석 > 시각화로 설명되고 있다.
  • 분석과정은 회사에 따라 다르다.

판다스(Pandas) 설치

 

  • Anaconda Prompt에서 pip list로 pandas 설치 확인

  • jupyter notebook에서 import
import pandas as pd
  • 사용되는 데이터 파일 - 노란색 부분

 

컬럼 : 국적코드, 성별, 입국객수, 전년동기

행은 0행 부터 시작한다.

즉, 노란색 부분을 추출하려면 A열에서 C열, 1행에서 7행만 추출한다.

 

 

 

 

 

 

 

데이터 수집 시 확인 사항

 

  • 날짜 확인 : 기준일로 사용
    - 년월일시분이 나타나 있는게 좋다.|
    - 최소한 년월까지는 있어야 한다. 최소 12개의 데이터를 확보할 수 있기 때문이다.
  • 범주형 데이터 확인 : 예로 남자 또는 여자와 같은 데이터
    - 범주형 데이터가 많은 데이터가 좋다. 비교대상이 많아 지기 때문이다.
    - 비교대상이 많아지면 데이터로 보여줄 수 있는게 많아진다

데이터 읽어오기

 

  •  파일 위치 지정
    - 상대경로로 지정한다.
file_path = "./files/sample_1.xlsx"
  • 피일 데이터 추출하기
    - file_path : 파일지정(위치 포함)
    - header : 칼럼명으로 사용할 행의 위치(default - 0)
    - skipfooter : 행의 가장 밑에서부터 포함하지 않을 행의 갯수(default - 0)
    - usecols : 가지고 올 열의 범위(A분터 C까지의 열)(default - data가 있는 모든 열)
sample_1 = pd.read_excel(file_path,
                        header=1,
                        skipfooter=2,
                        usecols="A:C")

 

  • csv, excel, json많이 사용
  • csv는 순수한 text 파일로 처리 과정이 따로 안들어가서 가볍다. 즉, 용량을 더 많이 담을 수 있다.
  • excel 파일 자체에 다양한 처리 과정이 같이 들어가기 때문에 무겁다.

 

 

 

 

 

  • 데이터 조회하기
sample_1

 

  • DataFrame 정보 확인하기
    - DataFrame 타입 : 행렬을 저장 관리하는 타입
    - info()함수는 데이터의 결측치(nan,null) 데이터 확인 가능
    - RangeIndex : 전체 행(row)의 갯수 0 to 5 총 6개
    - 전체 행의 갯수와 각 컬럼의 갯수가 안맞으면 결측 데이터가 존재한다는 의미.
sample_1.info()

 

# Non-Null = not null null이 아닌 데이터의 갯수
#  Dtype = 데이터 타입
#  object 문자열
# int 숫자

0 to 5 총 6개

 

 

 

 

 

  • 데이터프레임 출력
    - 데이터 행/열이 많은 경우 -> 기본 상위 5개, 하위 5개를 추출해서 보여줌
    - 데이터 행/열의 갯수가 작으면 모두 보여줌

  • head() : 상위 데이터 조회
    - 상위 5개
    sample_1.head()​

    - 상위 1개
    sample_1.head(1)​

 

  • tail() : 마지막 데이터 조회
    - default : 5개
    - 하위 5개
    sample_1.tail()​

    - 하위 1개
    sample_1.tail(1)​

  • 기초 통계 데이터
sample_1.describe()

 

- count : 데이터 행의 갯수
- mean : 데이터 평균
- std : 표준편차
- min : 최솟값
- max : 최댓값
- 25%, 50%(중앙값), 75% : 4분위수 데이터
        → 4분위수 데이터를 이용해서 이상치(이상한) 데이터 확인

- 기초통계 데이터는 숫자값을 가지는 컬럼에 대해서만 확인

 

 

 

데이터 조회하기

 

  • key 입력하고 value 받아오기
    - 국적코드 데이터 조회하기
sample_1["국적코드"]

 

- dtype: object

  → 데이터 하나하나의 타입이 object이다.

 

 

 

 

 

 

  • 타입 확인
    - 데이터 전체의 타입
type(sample_1["국적코드"])

 

- Series : 튜플과 모양이 같다. (사용법도 동일)
- {"국적코드" : (데이터, 데이터, ...)}

 

 

 

  • 2차원 행렬 형태로 조회
sample_1[["국적코드"]]

type(sample_1[["국적코드"]])

 

- [[ ]] : 2차원의 행렬인 DataFrame 타입

 

 

 

  • 국적코드와 성별 모두 조회하기
    - 컬럼 2개이상 조회시 [[ ]] 2차원 행렬 형태로 조회해야함
sample_1[["국적코드","성별"]]

 

 

기준년월 컬럼 추가하기

 

  • 2019-11 값을 추가하기
sample_1["기준년월"] = '2019-11'
sample_1

데이터 필터링 하기

 

  • 필터링 : 조건에 맞는 값 조회하기
  • 성별 중에 여성인 데이터만 추출하기
condition = sample_1["성별"] == "여성" 
condition


  • default 값은  True
sample_1[condition == False]


  • 한 줄로 조회하기
sample_1[(sample_1["성별"] == "여성") == True]

 


  • 객체 주소 전달 방식
    - 둘다 같은 곳을 바라 본다
    - sample_1이 바뀌면 sample_2가 바뀌고 sample_2가 바뀌면 sample_1이 바뀜
sample_2 = sample_1

 

  • copy()
    - 메모리 복제방식 (신규로 동일하게 생성 됨)

    - 신규로 만들어진 메모리 주소를 받아옴 (서로 영향 안받음)
    - 주소를 넣는 방식이 아니라 메모리를 복제하는 방식
sample_2 = sample_1.copy()
728x90
반응형
728x90
반응형

📝 문제

더보기

1. 문제설명

 얀에서는 매년 달리기 경주가 열립니다. 해설진들은 선수들이 자기 바로 앞의 선수를 추월할 때 추월한 선수의 이름을 부릅니다. 예를 들어 1등부터 3등까지 "mumu", "soe", "poe" 선수들이 순서대로 달리고 있을 때, 해설진이 "soe"선수를 불렀다면 2등인 "soe" 선수가 1등인 "mumu" 선수를 추월했다는 것입니다. 즉 "soe" 선수가 1등, "mumu" 선수가 2등으로 바뀝니다.선수들의 이름이 1등부터 현재 등수 순서대로 담긴 문자열 배열 players와 해설진이 부른 이름을 담은 문자열 배열 callings가 매개변수로 주어질 때, 경주가 끝났을 때 선수들의 이름을 1등부터 등수 순서대로 배열에 담아 return 하는 solution 함수를 완성해주세요.


2. 제한사항

  • 5 ≤ players의 길이 ≤ 50,000
    - players[i]는 i번째 선수의 이름을 의미합니다.
    - players의 원소들은 알파벳 소문자로만 이루어져 있습니다.
    - players에는 중복된 값이 들어가 있지 않습니다.
    - 3 ≤ players[i]의 길이 ≤ 10

  • 2 ≤ callings의 길이 ≤ 1,000,000
    - callingsplayers의 원소들로만 이루어져 있습니다.
    - 경주 진행중 1등인 선수의 이름은 불리지 않습니다.

3. 입출력 예

players callings result
["mumu", "soe", "poe", "kai", "mine"] ["kai", "kai", "mine", "mine"] ["mumu", "kai", "mine", "soe", "poe"]

4. 입출력 예 설명

  • 입출력 예 #1

 4등인 "kai" 선수가 2번 추월하여 2등이 되고 앞서 3등, 2등인 "poe", "soe" 선수는 4등, 3등이 됩니다. 5등인 "mine" 선수가 2번 추월하여 4등, 3등인 "poe", "soe" 선수가 5등, 4등이 되고 경주가 끝납니다. 1등부터 배열에 담으면 ["mumu", "kai", "mine", "soe", "poe"]이 됩니다.

 

✏️ 작성한 코드

 아래 작성한 코드는 answer를 players와 동일하다고 설정한 뒤 for문을 사용하여 callings와 players를 비교하고 있다. 두 값이 같으면  answer의 현재 인덱스 값이 players의 이전 인덱스 값으로 대체되고, answer의 이전 인덱스 값은 callings의 현재 인덱스 값으로 대체된다.

 입출력 예를 가지고 설명해 보자면, callings[0]인 "kai"와 players[0]인 " mumu" 값이 먼저 비교 되고 값이 같지 않으면 players의 인덱스는 1씩 증가되므로 " mumu", "soe", "poe", "kai", "mine" 순으로 비교 된다. 즉,  callings[0]은 players[3]인 "kai"와 값이 같으므로 이때의 인덱스를 기준으로 answer[3]은 players[3 - 1]인 "poe"로 대체 되고 answer[3-1]인 "poe"는 callings[0]인 "kai"로 바뀌게 되면서 내부 for문이 종료 된다.

 그리고 다시 callings[1]을 players[0]과 비교하면서 for문이 진행된다. 그러나 이렇게 진행할 경우 callings에 해당하는 player를 찾기 위해 반복문을 돌릴때 마다 callings과  players을 비교하게 되므로 효율적이지 못한 코드가 될 수 있다.

class Solution {
    public String[] solution(String[] players, String[] callings) {
        String[] answer = players ;
        for (int i = 0; i < callings.length;i++) {    
            for (int j = 0; j < players.length;j++) {
                if (callings[i].equals(players[j])) {
                 answer[j] = players[j - 1];
                 answer[j - 1] = callings[i];
                 break;
                 }
            }
        }
        return answer;       
    }
}

 

결과는 예시와 같이 나오지만 채점 하면 실행 시간 초과로 오답처리 된다. 아마 이 문제도 HashMap을 써야 하는 것 같다. 

✏️수정한 코드

 HaspMap을 사용해 본 코드이다.

  1.  for (int i = 0; i < players.length;i++) {map.put(players[i], i);}
    → 첫번째 for문으로 map에 players의 값을 저장한다.
  2. for (String name : callings)
    두번째 for문을 사용하면 callings에 있는 배열이 하나씩 name이란 변수에 담기면서 실행이 된다.
  3. int cur = map.get(name);
    먼저 배열의 첫번째 값인 "kai"가 name에 담기고 cur은 map에서의 name의 인덱스 값이 담긴다. 즉, map에 있는 "kai"의 인덱스 값인 3이 cur 값이 된다.
  4. map.put(name, cur - 1); 
    map에 (kai, (3 - 1)) 가 들어간다. 즉, map[2]인 "poe"가 "kai"로 변경된다.
  5. map.put(players[cur - 1], cur);
    map에 ( players[3 - 1] , 3) 이 들어간다. 즉, map[3]인 "kai"가  players[2]인  "poe"로 변경된다.
  6.  players[cur] = players[cur - 1];
     players[cur - 1] = name;
    호출된 플레이어와 이전 위치에 있던 플레이어를 서로 교체하여 플레이어들의 위치를 업데이트한다.
import java.util.*;

class Solution {
    public String[] solution(String[] players, String[] callings) {
        
        HashMap<String,Integer> map = new HashMap<>();
        
        for (int i = 0; i < players.length;i++) {   
            map.put(players[i], i);
        }
        
        for (String name : callings) {
            int cur = map.get(name);
            map.put(name, cur - 1);
            map.put(players[cur - 1], cur);
            players[cur] = players[cur - 1];
            players[cur - 1] = name;
        }
        return players;       
    }
}
728x90
반응형
728x90
반응형

📝문제

더보기

1. 문제 설명

다음은 어느 자동차 대여 회사의 자동차 대여 기록 정보를 담은CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블입니다. CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블은 아래와 같은 구조로 되어있으며, HISTORY_ID, CAR_ID, START_DATE, END_DATE는 각각 자동차 대여 기록 ID, 자동차 ID, 대여 시작일, 대여 종료일을 나타냅니다.


Column name Type Nullable 
HISTORY_ID INTEGER FALSE
CAR_ID INTEGER FALSE
START_DATE DATE FALSE
END_DATE DATE FALSE

 


2. 문제

CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에서 대여 시작일을 기준으로 2022년 8월부터 2022년 10월까지 총 대여 횟수가 5회 이상인 자동차들에 대해서 해당 기간 동안의 월별 자동차 ID 별 총 대여 횟수(컬럼명: RECORDS) 리스트를 출력하는 SQL문을 작성해주세요. 결과는 월을 기준으로 오름차순 정렬하고, 월이 같다면 자동차 ID를 기준으로 내림차순 정렬해주세요. 특정 월의 총 대여 횟수가 0인 경우에는 결과에서 제외해주세요.


3. 예시

예를 들어 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블이 다음과 같다면

HISTORY_ID CAR_ID START_DATE END_DATE
1 1 2022-07-27 2022-08-02
2 1 2022-08-03 2022-08-04
3 2 2022-08-05 2022-08-05
4 2 2022-08-09 2022-08-12
5 3 2022-09-16 2022-10-15
6 1 2022-08-24 2022-08-30
7 3 2022-10-16 2022-10-19
8 1 2022-09-03 2022-09-07
9 1 2022-09-18 2022-09-19
10 2 2022-09-08 2022-09-10
11 2 2022-10-16 2022-10-19
12 1 2022-09-29 2022-10-06
13 2 2022-10-30 2022-11-01
14 2 2022-11-05 2022-11-05
15 3 2022-11-11 2022-11-11

 

대여 시작일을 기준으로 총 대여 횟수가 5회 이상인 자동차는 자동차 ID가 1, 2인 자동차입니다. 월 별 자동차 ID별 총 대여 횟수를 구하고 월 오름차순, 자동차 ID 내림차순으로 정렬하면 다음과 같이 나와야 합니다.

MONTHCAR_IDRECORDS
MONTH CAR_ID RECORDS
8 2 2
8 1 2
9 2 1
9 1 3
10 2 2

✏️작성한 코드

 어려웠던 점은 조건을 줄 때 CAR_ID에 대한 조건을 주고 전체 행에 대한 조건을 따로 줘야 한다는 것이다.  먼저 대여 시작일을 기준으로 2022년 8월 부터 2022년 10월까지 총 대여 횟수가 5회 이상인 자동차들에 대한 조건을 서브쿼리로 준다. 그리고 해당 기간 동안의 월별 CAR_ID 별 총 대여 횟수 리스트를 출력한다.

 작성해놓고 왜 이렇게 적었는지 설명을 못하겠다... 헷

SELECT SUBSTRING(START_DATE,6,2) AS MONTH
		, CAR_ID
    	, COUNT(CAR_ID) AS RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE CAR_ID IN (
    		SELECT CAR_ID 
    			FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
   					 WHERE SUBSTRING(START_DATE,1,7) BETWEEN '2022-08' AND '2022-10'
    		GROUP BY CAR_ID
    		HAVING COUNT(CAR_ID) >= 5)
	AND SUBSTRING(START_DATE,1,7) BETWEEN '2022-08' AND '2022-10'
GROUP BY SUBSTRING(START_DATE,6,2), CAR_ID
ORDER BY MONTH, CAR_ID DESC;

 

코드 실행 시 아래와 같은 형식으로 데이터가 출력된다.

728x90
반응형

+ Recent posts