├── .gitignore ├── BOJ ├── [10282] 해킹 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [11000] 강의실 배정 │ ├── HyeW │ │ ├── ClassroomAssignment.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_11000.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── README.md │ │ └── boj11000.java │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [11279] 최대 힙 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_11279.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [11444] 피보나치 수 6 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [11660] 구간 합 구하기 5 │ ├── HyeW │ │ ├── README.md │ │ └── SectionSum5.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_11660.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [1167] 트리의 지름 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_1167.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [11726] 2xn 타일링 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_11726.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [12100] 2048 (Easy) │ ├── HyeW │ │ ├── Easy2048.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_12100.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [1238] 파티 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_1238.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [13549] 숨바꼭질 3 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_13549.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [14500] 테트로미노 │ ├── HyeW │ │ ├── README.md │ │ └── Tetromino.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_14500.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── README.md │ │ └── boj14500.java │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [14502] 연구소 │ ├── HyeW │ │ ├── Laboratory.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_14502.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [14676] 영우는 사기꾼 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [14891] 톱니바퀴 │ ├── HyeW │ │ ├── Gear.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_14891.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [15565] 귀여운 라이언 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ └── jungu12 │ │ ├── Main.java │ │ └── README.md ├── [1563] 개근상 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ └── jungu12 │ │ ├── Main.java │ │ └── README.md ├── [16234] 인구 이동 │ ├── HyeW │ │ ├── PopulationMovement.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_16234.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [16236] 아기 상어 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_16236.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [16472] 고냥이 │ ├── HyeW │ │ ├── Cat.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_16472.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [16724] 피리 부는 사나이 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [16928] 뱀과 사다리 게임 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_16928.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [16946] 벽 부수고 이동하기 4 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [17070] 파이프 옮기기 1 │ ├── HyeW │ │ ├── CarryPipe.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_17070.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [17136] 색종이 붙이기 │ ├── HyeW │ │ ├── AttachPaper.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_17136.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [17144] 미세먼지 안녕! │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_17144.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [17404] RGB거리 2 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [17406] 배열 돌리기 4 │ ├── HyeW │ │ ├── README.md │ │ └── TurnArray4.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_17406.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [1759] 암호 만들기 │ ├── HyeW │ │ ├── MakePassword.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_1759.java │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── README.md │ │ └── boj1759.java │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [17779] 게리맨더링 2 │ ├── HyeW │ │ ├── Gerrymandering2.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_17779.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [1865] 웜홀 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_1865.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [1890] 점프 │ ├── HyeW │ │ ├── Jump.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_1890.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── RAEDME.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [1918] 후위 표기식 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_1918.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [19237] 어른 상어 │ ├── HyeW │ │ ├── AdultShark.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_19237.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [1932] 정수 삼각형 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_1932.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [20166] 문자열 지옥에 빠진 호석 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_20166.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [20168] 골목 대장 호석 - 기능성 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_20168.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [2056] 작업 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ └── ksg2388 │ │ ├── Main.js │ │ └── README.md ├── [2156] 포도주 시식 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_2156.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [2206] 벽 부수고 이동하기 │ ├── HyeW │ │ ├── CrashWallAndMove.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_2206.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [2263] 트리의 순회 │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_2263.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [2527] 직사각형 │ ├── HyeW │ │ ├── README.md │ │ └── Rectangle_Main.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_2527.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [2529] 부등호 │ ├── HyeW │ │ ├── InequalitySign.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_2529.java │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── README.md │ │ └── boj2529.java │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [26215] 눈 치우기 │ ├── HyeW │ │ ├── CleanSnow.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_26215.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── README.md │ │ └── boj26215.java │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [2931] 가스관 │ ├── HyeW │ │ ├── GasPipe.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_2931.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [3020] 개똥벌레 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [3190] 뱀 │ ├── HyeW │ │ ├── README.md │ │ └── Snake.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_3190.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── README.md │ │ └── main.java ├── [3584] 가장 가까운 공통 조상 │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ └── jungu12 │ │ ├── Main.java │ │ └── README.md ├── [4803] 트리 │ ├── HyeW │ │ ├── README.md │ │ └── Tree.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_4803.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── README.md │ │ └── main.java ├── [7576] 토마토 │ ├── HyeW │ │ ├── README.md │ │ └── Tomato.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_7576.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [9019] DSLR │ ├── HyeW │ │ ├── Main.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_9019.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── [9465] 스티커 │ ├── HyeW │ │ ├── README.md │ │ └── Sticker.java │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_9465.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md └── [9935] 문자열 폭발 │ ├── HyeW │ ├── ExplodeString.java │ └── README.md │ ├── SUbbb │ ├── Main.java │ └── README.md │ ├── asever0318 │ ├── Main_9935.java │ └── README.md │ ├── jungu12 │ ├── Main.java │ └── README.md │ ├── ksg2388 │ ├── Main.java │ └── README.md │ └── yeahLim │ ├── Main.java │ └── README.md ├── CodeTree ├── 꼬리잡기놀이 │ ├── HyeW │ │ ├── CatchTail.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_꼬리잡기놀이.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── 싸움땅 │ ├── HyeW │ │ ├── FightDang.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── Main_싸움땅.java │ │ └── README.md │ ├── jungu12 │ │ ├── Main.java │ │ └── README.md │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md ├── 코드트리 빵 │ ├── HyeW │ │ ├── CodeTreeBread.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_코드트리빵.java │ ├── ksg2388 │ │ ├── Main.java │ │ └── README.md │ └── yeahLim │ │ ├── Main.java │ │ └── README.md └── 팩맨 │ ├── HyeW │ ├── README.md │ └── Solution.java │ ├── SUbbb │ ├── Main.java │ └── README.md │ ├── asever0318 │ ├── Main_팩맨.java │ └── README.md │ ├── jungu12 │ ├── Main.java │ └── README.md │ ├── ksg2388 │ ├── README.md │ └── Solution.java │ └── yeahLim │ ├── Main.java │ └── README.md ├── Programmers ├── [118668] 코딩 테스트 공부 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_118668.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [118669] 등산코스 정하기 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_118669.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [12913] 땅따먹기 │ ├── HyeW │ │ ├── READMe.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_12913.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [12938] 최고의 집합 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_12938.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [131130] 혼자 놀기의 달인 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_131130.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ └── ksg2388 │ │ ├── README.md │ │ └── Solution.js ├── [131704] 택배상자 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_131704.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Soultion.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [142085] 디펜스 게임 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_142085.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [148653] 마법의 엘리베이터 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_148653.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [150366] 표 병합 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ └── ksg2388 │ │ ├── README.md │ │ └── Solution.js ├── [150367] 표현 가능한 이진트리 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_150367.java │ └── ksg2388 │ │ ├── README.md │ │ └── Solution.java ├── [150369] 택배 배달과 수거하기 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_150369.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ └── ksg2388 │ │ ├── README.md │ │ └── Solution.js ├── [152995] 인사고과 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_152995.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [154540] 무인도 여행 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_154540.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [155651] 호텔 대실 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ └── jungu12 │ │ ├── README.md │ │ └── Solution.java ├── [159993] 미로 탈출 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_159993.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [160585] 혼자서 하는 틱택토 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_160585.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ └── ksg2388 │ │ ├── README.md │ │ └── Solution.js ├── [161988] 연속 펄스 부분 수열의 합 │ ├── README.md │ ├── Solution.js │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_161988.java │ └── jungu12 │ │ ├── README.md │ │ └── Solution.java ├── [169199] 리코쳇 로봇 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_169199.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [172927] 광물 캐기 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_172927.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ └── ksg2388 │ │ ├── README.md │ │ └── Solution.js ├── [17683] 방금그곡 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_17683.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [181188] 요격 시스템 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_181188.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [42584] 주식가격 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_42584.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Soultion.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [42860] 조이스틱 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_42860.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [49994] 방문 길이 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_49994.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── Main.js │ │ └── README.md │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [62048] 멀쩡한 사각형 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_62048.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Soultion.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [67259] 경주로 건설 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_67259.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [68646] 풍선 터트리기 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ └── jungu12 │ │ ├── README.md │ │ └── Solution.java ├── [77485] 행렬 테두리 회전하기 │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_77485.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ └── ksg2388 │ │ ├── README.md │ │ └── Solution.js ├── [92341] 주차 요금 계산 │ ├── HyeW │ │ ├── README.md │ │ └── Solution.java │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_92341.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.js │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java └── [92342] 양궁대회 │ ├── HyeW │ ├── README.md │ └── Solution.java │ ├── SUbbb │ ├── README.md │ └── Solution.java │ ├── asever0318 │ ├── README.md │ └── Solution_92342.java │ ├── jungu12 │ ├── README.md │ └── Solution.java │ └── ksg2388 │ ├── README.md │ └── Solution.js ├── README.md ├── SWEA ├── [1225] 암호생성기 │ ├── HyeW │ │ ├── PasswordGenerator.java │ │ └── README.md │ ├── SUbbb │ │ ├── Main.java │ │ └── README.md │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_1225.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── swea1225.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [1234] 비밀번호 │ ├── HyeW │ │ ├── Password.java │ │ └── README.md │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_1234.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [2383] 점심 식사시간 │ ├── HyeW │ │ ├── LunchTime.java │ │ └── README.md │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_2383 │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [3752] 가능한 시험 점수 │ ├── HyeW │ │ ├── PossibleScore.java │ │ └── README.md │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── README.md │ │ └── Solution_3752.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── Solution.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java ├── [5215] 햄버거 다이어트 │ ├── HyeW │ │ ├── HamburgerDiet.java │ │ └── README.md │ ├── SUbbb │ │ ├── README.md │ │ └── Solution.java │ ├── asever0318 │ │ ├── READMD.md │ │ └── Solution_5215.java │ ├── jungu12 │ │ ├── README.md │ │ └── Solution.java │ ├── ksg2388 │ │ ├── README.md │ │ └── swea5215.java │ └── yeahLim │ │ ├── README.md │ │ └── Solution.java └── [7465] 창용 마을 무리의 개수 │ ├── HyeW │ ├── README.md │ └── VillageNumber.java │ ├── SUbbb │ ├── README.md │ └── Solution.java │ ├── asever0318 │ ├── README.md │ └── Solution_7465.java │ ├── jungu12 │ ├── README.md │ └── Solution.java │ ├── ksg2388 │ ├── README.md │ └── Solution.java │ └── yeahLim │ ├── README.md │ └── Solution.java ├── leetcode └── check-if-n-and-its-double-exist │ └── java │ ├── README.md │ └── check-if-n-and-its-double-exist.java └── programmers └── [42628] 이중우선순위큐 └── java ├── 42628.java └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore File ## 2 | .DS_Store 3 | .idea 4 | -------------------------------------------------------------------------------- /BOJ/[10282] 해킹/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [10282] 해킹 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 다익스트라 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void startHacking() { 11 | Queue pq = new PriorityQueue<>((o1, o2) -> { 12 | return o1[1] - o2[1]; 13 | }); 14 | pq.add(new int[] { C, 0 }); 15 | while (!pq.isEmpty()) { 16 | int[] cur = pq.poll(); 17 | for (int i = 0; i < dependency[cur[0]].size(); i++) { 18 | int[] destination = dependency[cur[0]].get(i); 19 | if (cur[1] + destination[1] < hackedTime[destination[0]]) { 20 | hackedTime[destination[0]] = cur[1] + destination[1]; 21 | pq.add(new int[] { destination[0], hackedTime[destination[0]] }); 22 | } 23 | } 24 | } 25 | } 26 | ``` 27 | 28 | - 우선순위큐를 사용하는 다익스트라로 시간이 오래 걸리는 경로는 나중에 보도록 하여 시간초과를 방지하였다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 처음에는 의존도를 2차원 배열로 사용해서 메모리 초과를 봤다. 33 | - 2차원 배열을 리스트로 바꾸니 시간 초과가 났다. (DFS로 풀었음) 34 | - 그제서야 다익스트라를 떠올렸다.. 35 | -------------------------------------------------------------------------------- /BOJ/[10282] 해킹/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [10282] 해킹 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 다익스트라 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int i = 0; i < d; i++) { 11 | st = new StringTokenizer(br.readLine()); 12 | int a = Integer.parseInt(st.nextToken()); 13 | int b = Integer.parseInt(st.nextToken()); 14 | int s = Integer.parseInt(st.nextToken()); 15 | graph[b].add(new Node(a, s)); 16 | } 17 | ``` 18 | - a가 b에 의존하기 때문에 a -> b가 아니라 b -> a이다. 19 | 20 | ```java 21 | if (dist[cur.n] < cur.weight) { 22 | continue; 23 | } 24 | ``` 25 | - visited 대신에 dist와 현재 가중치를 비교해서 클 경우는 탐색하지 않은 식으로 사용할 수 있다. 26 | 27 | 28 | ## :black_nib: **Review** 29 | 30 | - 네트워크가 들어가면 그래프 이론일 확률이 높아진다는 것을 배웠다. 31 | - 다익스트라 오랜만인데 다시 정리할 수 있어서 좋았다. 32 | -------------------------------------------------------------------------------- /BOJ/[11000] 강의실 배정/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [11000] 강의실 배정 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐, 그리디 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static int countRooms() { 11 | Queue endTimes = new PriorityQueue<>(); 12 | endTimes.add(times.poll().end); 13 | while (!times.isEmpty()) { 14 | ClassTime current = times.poll(); 15 | if (current.start >= endTimes.peek()) { 16 | endTimes.poll(); 17 | } 18 | endTimes.add(current.end); 19 | } 20 | return endTimes.size(); 21 | } 22 | ``` 23 | 24 | - 강의 종료 시간을 저장하는 `endTimes` 25 | - 강의 시간 정보를 탐색하면서 현재 가장 먼저 끝나는 강의에 이어서 진행할 수 있는 강의가 있다면, 현재 가장 먼저 끝나는 강의 정보를 큐에서 삭제하고, 현재 강의의 종료 시간을 큐에 삽입한다. 26 | - 마지막에 큐의 크기가 사용할 수 있는 최소의 강의실 개수이다. 27 | 28 | ## :black_nib: **Review** 29 | - 이전에 C++로 구현했었는데, 다시 보니 우선순위 큐를 사용해야 하는 문제임은 쉽게 파악할 수 있었으나, 구현이 오래 걸렸다. -------------------------------------------------------------------------------- /BOJ/[11000] 강의실 배정/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [11000] 강의실 배정 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐, 백 트래킹 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void pro() { 11 | Queue lecture = new PriorityQueue<>(); 12 | lecture.add(endTimes.poll()); 13 | startTimes.poll(); 14 | int size = startTimes.size(); 15 | for(int i = 0 ; i < size; i ++) { 16 | while(!startTimes.isEmpty() && !lecture.isEmpty()) { 17 | if(lecture.peek() <= startTimes.poll()) 18 | lecture.poll(); 19 | } 20 | lecture.add(endTimes.poll()); 21 | if(lecture.size() > result) 22 | result = lecture.size(); 23 | } 24 | System.out.println(result); 25 | } 26 | ``` 27 | - 우선순위 큐 두개에 강의 시작 시간, 강의 종료 시간을 입력 받았다. 28 | - 총 강의 수 만큼 for문을 돌며, 강의 종료 시간을 lecture priorityqueue에 넣고, lecture 안에 다음 강의 시작 시간 보다 더 작은 값은 버려준다. 29 | 30 | 31 | ## :black_nib: **Review** 32 | - 우선순위 큐 메소드 활용이 다소 미숙하여 구현 시간이 오래걸렸다. 33 | - peek() poll() 등 여러 메소드의 queue가 비었을 때 예외처리에 대해 알게 되었다. 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /BOJ/[11000] 강의실 배정/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 우선순위큐와 그리디 알고리즘을 이용 4 | 5 | ## 중요 구현 로직 및 설명 6 | 7 | 우선순위 큐를 사용해서 강의 종료 시간을 기준으로 오름차순 정렬 8 | 9 | 1. 배열을 시작 시간 기준으로 정렬 10 | 2. 큐가 빈 경우 데이터 입력 11 | 3. 큐에 값이 있는 경우 새로 들어갈 강의의 시작 시간이 큐의 가장 앞의 값의 종료 시간이후라면 기존의 큐의 값을 빼고 새로 큐에 삽입 12 | 4. 아니라면 기존 데이터를 놔두고 새로운 큐를 삽입 13 | 5. 과정을 반복하고 마지막에 큐에 남아있는 값의 길이 반환 14 | image 15 | 가장 일찍 끝나는 종료시간과 다음 강의의 시작시간의 값을 비교해서 시작시간이 강의 종료시간보다 느린 경우는 그 강의실을 이어서 사용하고 아닌 경우 새 강의실을 배정한다. 16 | 17 | ## 풀이 후기 18 | 19 | 우선순위큐를 처음 사용해서 이렇게 사용하는 것이 맞는지 잘 모르겠다. 앞으로 비슷한 유형의 다른 문제를 더 풀어봐야겠다. 20 | -------------------------------------------------------------------------------- /BOJ/[11279] 최대 힙/HyeW/Main.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.io.*; 3 | 4 | public class Main { 5 | static Queue maxHeap; 6 | static StringBuilder sb; 7 | 8 | public static void main(String[] args) throws IOException { 9 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 10 | sb = new StringBuilder(); 11 | 12 | int n = Integer.parseInt(br.readLine()); 13 | maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1); 14 | 15 | for(int i = 0; i < n; i++) { 16 | int v = Integer.parseInt(br.readLine()); 17 | if(v == 0) { 18 | getMaxValue(); 19 | } 20 | maxHeap.add(v); 21 | } 22 | System.out.println(sb); 23 | } 24 | 25 | private static void getMaxValue() { 26 | if(maxHeap.size() == 0) { 27 | sb.append(0).append("\n"); 28 | return; 29 | } 30 | sb.append(maxHeap.poll()).append("\n"); 31 | } 32 | } -------------------------------------------------------------------------------- /BOJ/[11279] 최대 힙/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [11279] 최대 힙 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1); 11 | for(int i = 0; i < n; i++) { 12 | int v = Integer.parseInt(br.readLine()); 13 | if(v == 0) { 14 | getMaxValue(); 15 | } 16 | maxHeap.add(v); 17 | } 18 | System.out.println(sb); 19 | ``` 20 | - `PrioriyQueue`를 사용해서 문제를 해결했다. 21 | 22 | ## :black_nib: **Review** 23 | 24 | - 이 문제는 우선순위 큐를 사용할 수 있는지 묻는 문제인건가... 25 | - 연산 개수 100,000개이기때문에 출력을 하려면 StringBuilder를 하는게 좋다. -------------------------------------------------------------------------------- /BOJ/[11279] 최대 힙/SUbbb/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.*; 5 | 6 | public class Main { 7 | 8 | public static void main(String[] args) throws IOException { 9 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 10 | int T = Integer.parseInt(br.readLine()); 11 | StringBuilder answer = new StringBuilder(); 12 | Queue heap = new PriorityQueue<>(Comparator.reverseOrder()); 13 | 14 | for (int count = 0; count < T; count++) { 15 | int number = Integer.parseInt(br.readLine()); 16 | if (number == 0) { 17 | if (heap.isEmpty()) { 18 | answer.append(0); 19 | } else { 20 | answer.append(heap.poll()); 21 | } 22 | answer.append("\n"); 23 | } 24 | 25 | if (number > 0) { 26 | heap.add(number); 27 | } 28 | } 29 | 30 | System.out.print(answer); 31 | } 32 | } -------------------------------------------------------------------------------- /BOJ/[11279] 최대 힙/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [11279] 최대 힙 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | Queue heap = new PriorityQueue<>(Comparator.reverseOrder()); 11 | 12 | for (int count = 0; count < T; count++) { 13 | int number = Integer.parseInt(br.readLine()); 14 | if (number == 0) { 15 | if (heap.isEmpty()) { 16 | answer.append(0); 17 | } else { 18 | answer.append(heap.poll()); 19 | } 20 | answer.append("\n"); 21 | } 22 | 23 | if (number > 0) { 24 | heap.add(number); 25 | } 26 | } 27 | ``` 28 | 29 | - 우선순위 큐를 사용했다. 30 | 31 | ## :black_nib: **Review** 32 | 33 | - 우선순위 큐를 직접 구현하는 문제인 줄 알았으나, 입력 범위가 크지 않아서 우선순위 큐를 활용하면 충분히 가능해보였다. -------------------------------------------------------------------------------- /BOJ/[11279] 최대 힙/jungu12/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.Collections; 5 | import java.util.PriorityQueue; 6 | 7 | public class Main { 8 | public static void main(String[] args) throws IOException { 9 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 10 | 11 | PriorityQueue pq = new PriorityQueue<>((o1, o2) -> o2 - o1); 12 | 13 | int N = Integer.parseInt(br.readLine()); 14 | int x; 15 | for(int i = 0; i < N; i++) { 16 | x = Integer.parseInt(br.readLine()); 17 | if(x != 0) { 18 | pq.add(x); 19 | continue; 20 | } 21 | if(!pq.isEmpty()) { 22 | System.out.println(pq.poll()); 23 | continue; 24 | } 25 | System.out.println(0); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /BOJ/[11279] 최대 힙/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [11279] 최대 힙 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | PriorityQueue pq = new PriorityQueue<>((o1, o2) -> o2 - o1); 11 | 12 | int N = Integer.parseInt(br.readLine()); 13 | int x; 14 | for(int i = 0; i < N; i++) { 15 | x = Integer.parseInt(br.readLine()); 16 | if(x != 0) { 17 | pq.add(x); 18 | continue; 19 | } 20 | if(!pq.isEmpty()) { 21 | System.out.println(pq.poll()); 22 | continue; 23 | } 24 | System.out.println(0); 25 | } 26 | ``` 27 | 28 | - 최대 값을 출력하고 제거해야하니 내림차순으로 우선순위 큐를 정렬해준다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 자바에는 heap을 구현한 우선순위 큐 class가 있어 정말 간단하게 풀 수 있는 문제였다 ! 33 | -------------------------------------------------------------------------------- /BOJ/[11279] 최대 힙/yeahLim/Main.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.io.*; 3 | 4 | public class Main { 5 | public static void main(String[] args) throws IOException { 6 | 7 | /* 입력 및 변수 초기화 */ 8 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | int n = Integer.parseInt(br.readLine()); 10 | PriorityQueue pq = new PriorityQueue<>(Comparator.reverseOrder()); 11 | StringBuilder sb = new StringBuilder(); 12 | 13 | /* Heap : priorityqueue로 최대 힙 구하기 */ 14 | for(int i=0; i pq = new PriorityQueue<>(Comparator.reverseOrder()); 11 | 12 | 13 | /* Heap : priorityqueue로 최대 힙 구하기 */ 14 | for(int i=0; i 20 | 그래서 임의의 노드(0번 노드)를 DFS 하여 지름의 끝점을 구하고 그 점을 이용해 트리의 지름을 구한다
21 | 22 | ```java 23 | private static void getEndPoint(int v, int w) { 24 | if(w > maxWeight) { 25 | maxWeight = w; 26 | endPoint = v; 27 | } 28 | 29 | for(Node nxt : graph[v]) { 30 | if(visited[nxt.v]) { 31 | continue; 32 | } 33 | 34 | visited[nxt.v] = true; 35 | getEndPoint(nxt.v, w+nxt.w); 36 | visited[nxt.v] = false; 37 | } 38 | } 39 | ``` 40 | 모든 노드를 확인하며 가장 긴 선분을 찾는다.
41 | 42 | ## :black_nib: **Review** 43 | 44 | - 예전에 풀어봤던 문제라서 바로 풀 수 있었다. 45 | -------------------------------------------------------------------------------- /BOJ/[1167] 트리의 지름/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [1167] 트리의 지름 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | dfs 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | findMax(1, 0); 11 | visited = new boolean[V+1]; 12 | max = 0; 13 | findMax(y, 0); 14 | 15 | System.out.println(max); 16 | ``` 17 | 18 | - dfs를 총 2번 실행하는데 19 | - 1. 임의의 정점(여기서는 0으로 설정했다)에서 가장 먼 정점 y 찾기 20 | - 2. y에서 가장 먼 정점 찾기 21 | - y에서 가장 먼 정점까지의 경로가 트리의 지름이 된다. 22 | 23 | ```java 24 | static void findMax(int v, int sum) { 25 | if(max < sum) { 26 | max = sum; 27 | y = v; 28 | } 29 | 30 | visited[v] = true; 31 | 32 | for(int i = 0; i < linked[v].size(); i++) { 33 | Vertex next = linked[v].get(i); 34 | 35 | if(visited[next.to]) { 36 | continue; 37 | } 38 | 39 | findMax(next.to, sum+next.w); 40 | } 41 | } 42 | ``` 43 | 44 | - v정점에서 연결된 정점을 탐색하면서 방문하지 않은 정점이면 해당 정점에서 연결된 정점을 또 탐색하는 방식으로 끝까지 확인한다. 45 | - 정점 사이의 거리를 sum 변수에 거리를 저장하고 재귀함수 호출할 때 넘겨주어서 거리 max 값을 갱신한다. 최종적으로 가장 먼 정점이 y에 저장된다. 46 | 47 | ## :black_nib: **Review** 48 | 49 | - 답 보고 풀었다.. 트리의 성질을 모르면 못풀 것 같다. 50 | -------------------------------------------------------------------------------- /BOJ/[1167] 트리의 지름/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [1167] 트리의 지름 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void findEnd(int vertex, int length) { 11 | if (length > max) { 12 | max = length; 13 | endVertex = vertex; 14 | } 15 | 16 | for (int i = 0; i < graph[vertex].size(); i++) { 17 | Node current = graph[vertex].get(i); 18 | if (visited[current.vertex]) { 19 | continue; 20 | } 21 | 22 | visited[current.vertex] = true; 23 | findEnd(current.vertex, length + current.length); 24 | visited[current.vertex] = false; 25 | } 26 | } 27 | 28 | ``` 29 | 30 | - 아무 Vertex에서 DFS로 가장 거리가 먼 Vertex를 찾으면 그 Vertex가 트리의 한쪽 끝이다. 31 | - 위에서 찾은 트리의 한쪽 끝 Vertex로 부터 가장 거리가 먼 Vertex를 찾으면 또 다른 트리의 한쪽 끝을 찾은 것이다. 32 | - 위 두 점을 이용하여 트리의 지름을 구할 수 있다. 33 | - 짧게 요약하면 DFS 두번 돌리면 트리의 지름을 구할 수 있다~ 34 | 35 | ## :black_nib: **Review** 36 | 37 | - 위에 언급한 아이디어를 떠올리는 것이 쉽지 않은 문제이다. 38 | -------------------------------------------------------------------------------- /BOJ/[1167] 트리의 지름/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [1167] 트리의 지름 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 트리, DFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | if (depth == 1) { 11 | start = cur; 12 | } 13 | ``` 14 | 15 | - 트리의 정보를 입력 받으면서 리프노드인 경우의 위치를 저장해둔다. 16 | 17 | ```java 18 | visited = new boolean[v + 1]; 19 | visited[start] = true; 20 | dfs(start, 0); 21 | 22 | visited = new boolean[v + 1]; 23 | visited[nextPoint] = true; 24 | dfs(nextPoint, 0); 25 | ``` 26 | 27 | - DFS를 이용해 시작 노드에서 가장 먼 거리에 있는 노드를 찾고 그 위치를 `nextPoint`에 저장해둔다. 28 | - `nextPoint`에서 다시 DFS를 이용해 가장 먼 거리에 있는 노드를 찾아 그 거리를 저장한다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 저번에 비슷한 문제를 풀어봐서 바로 그 방법을 적용했더니 풀렸다. 33 | - 트리의 지름을 구하는 방식 기억해둬야겠다. 34 | -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/HyeW/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | public class Main { 4 | static int[] tile; 5 | 6 | public static void main(String[] args) throws IOException{ 7 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 8 | 9 | int n = Integer.parseInt(br.readLine()); 10 | // 피보나치 수열 초기화 11 | tile = new int[n+1]; 12 | tile[0] = 1; 13 | tile[1] = 1; 14 | 15 | System.out.println(tiling(n)); 16 | } 17 | 18 | private static int tiling(int n) { 19 | if(tile[n] != 0) { 20 | return tile[n]; 21 | } 22 | return tile[n] = (tiling(n-1) + tiling(n-2))%10007; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [11726] 2xn 타일링 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP, 재귀 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 이 문제는 직사각형의 가로길이가 커질 때마다 채우는 방법 가지수는 피보나치 수열과 같다. 10 | 11 | ```java 12 | private static int tiling(int n) { 13 | if(tile[n] != 0) { 14 | return tile[n]; 15 | } 16 | return tile[n] = (tiling(n-1) + tiling(n-2))%10007; 17 | } 18 | ``` 19 | - DP와 재귀함수를 사용하여 피보나치 수열을 구현했다. 20 | 21 | ## :black_nib: **Review** 22 | - 공간을 2x1 로 하나씩 늘릴 때마다 현재 공간을 1x2 블럭으로 채우면 n-2번째 방법수 만큼의 경우의 수가 나오고, 2x1 블럭으로 채우면 n-1번째 방법수 만큼 나오기 때문에 피보나치 수열을 사용했다. 23 | - 직접 그려보며 깨달았다. -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/SUbbb/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | public class Main { 6 | private static final int DIV = 10007; 7 | 8 | public static void main(String[] args) throws IOException { 9 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 10 | int N = Integer.parseInt(br.readLine()); 11 | 12 | if (N <= 2) { 13 | System.out.print(N); 14 | return; 15 | } 16 | 17 | int doublePrev = 1; 18 | int prev = 2; 19 | int now = 0; 20 | 21 | for (int index = 2; index < N; index++) { 22 | now = (doublePrev + prev) % DIV; 23 | doublePrev = prev; 24 | prev = now; 25 | } 26 | 27 | System.out.print(now); 28 | } 29 | } -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [11726] 2xn 타일링 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int doublePrev = 1; 11 | int prev = 2; 12 | int now = 0; 13 | 14 | for (int index = 2; index < N; index++) { 15 | now = (doublePrev + prev) % DIV; 16 | doublePrev = prev; 17 | prev = now; 18 | } 19 | ``` 20 | 21 | - 변수 3개를 사용해서 피보나치 수를 구하는 방식으로 N - 1까지의 경우의 수를 구한다. 22 | 23 | ## :black_nib: **Review** 24 | 25 | - 처음에는 배열을 이용해서 피보나치 수를 구하는 방식으로 구현했는데, 피보나치 수를 구할 때 굳이 배열을 사용하지 않고 변수만으로도 가능하다는 것이 생각나서 변수 3개를 사용하는 방식으로 수정했다. -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/asever0318/Main_11726.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | public class Main { 4 | static int N; 5 | static int[] tile; 6 | 7 | public static void main(String[] args) throws IOException { 8 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | 10 | N = Integer.parseInt(br.readLine()); 11 | tile = new int[1001]; 12 | 13 | System.out.println(tiling()); 14 | 15 | } 16 | 17 | public static int tiling() { 18 | 19 | tile[1] = 1; 20 | tile[2] = 2; 21 | 22 | for(int i = 3; i <= N; i++) { 23 | tile[i] = (tile[i-1] + tile[i-2]) % 10007; 24 | } 25 | 26 | return tile[N]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [11726] 2xn 타일링 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 다이나믹 프로그래밍 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | public static int tiling() { 11 | 12 | tile[1] = 1; 13 | tile[2] = 2; 14 | 15 | for(int i = 3; i <= N; i++) { 16 | tile[i] = (tile[i-1] + tile[i-2]) % 10007; 17 | } 18 | 19 | return tile[N]; 20 | } 21 | ``` 22 | - n=1일 때 경우의 수는 1가지, n=2일 때 경우의 수는 2가지, 이후 n=3부터는 n-1의 경우의 수 + n-2의 경우의 수를 한 것과 같으므로 위와 같은 점화식을 세울 수 있었다 23 | 24 | ## :black_nib: **Review** 25 | 26 | - 머리로 생각 하기보다는 그림을 그리니까 쉽게 이해할 수 있었던 문제였다. 27 | - int형 배열로 구현했을 때 오버플로우가 발생했다. int 자료형이 표현할 수 있는 범위를 넘어서서 그런 거였다. 매번 다음 값을 찾을 때 마다 %연산을 해주는 것으로 해결할 수 있었다. 자료형의 범위에 대해서 공부할 수 있었던 문제였다. 28 | -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/jungu12/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | 5 | public class Main { 6 | public static void main(String[] args) throws IOException { 7 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 8 | 9 | int N = Integer.parseInt(br.readLine()); 10 | int prevPrevNum = 1; 11 | int prevNum = 1; 12 | int curNum = 1; 13 | 14 | for(int i = 2; i <= N ; i++) { 15 | prevPrevNum = prevNum; 16 | prevNum = curNum; 17 | curNum = (prevPrevNum + prevNum) % 10007; 18 | } 19 | 20 | System.out.println(curNum); 21 | } 22 | } -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [11726]2xn 타일링 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int prevPrevNum = 1; 11 | int prevNum = 1; 12 | int curNum = 1; 13 | 14 | for(int i = 2; i <= N ; i++) { 15 | prevPrevNum = prevNum; 16 | prevNum = curNum; 17 | curNum = (prevPrevNum + prevNum) % 10007; 18 | } 19 | 20 | System.out.println(curNum); 21 | ``` 22 | 23 | - n(n > 2)번째 방법의 수는 n-1번째의 방법들에 세로 1x2 타일을 붙이는 경우 + n-2번째의 방법들에 2x1타일을 두개 붙이는 경우이다. 24 | - 즉, 피보나치 수열을 구현하면 문제를 풀 수 있다! 25 | 26 | ## :black_nib: **Review** 27 | 28 | - 비교적 쉬운 DP문제였으나, 값들을 10007로 나누어서 저장해야 하는 것을 바로 생각하지 못하였다. 29 | -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/ksg2388/Main.js: -------------------------------------------------------------------------------- 1 | let fs = require('fs'); 2 | let input = fs.readFileSync('/dev/stdin').toString(); 3 | 4 | let n = Number(input); 5 | let prev = 1; // n = 0부터 시작 6 | let cur = 1; // n = 1인 경우 7 | 8 | if (n > 1) { 9 | for (let i = 2; i <= n; i++) { 10 | [cur, prev] = [(cur + prev) % 10007, cur]; 11 | } 12 | } 13 | 14 | console.log(cur); 15 | -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [11726] 2xn 타일링 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | let prev = 1; // n = 0부터 시작 11 | let cur = 1; // n = 1인 경우 12 | 13 | if (n > 1) { 14 | for (let i = 2; i <= n; i++) { 15 | [cur, prev] = [(cur + prev) % 10007, cur]; 16 | } 17 | } 18 | ``` 19 | 20 | - 현재 값과 이전 값을 이용해 다음 값을 구하는 식으로 피보나치 수열을 이용하여 문제를 해결하였다. 21 | 22 | ## :black_nib: **Review** 23 | 24 | - 처음에는 피보나치 수열인지 파악하지 못했지만 규칙을 따라가다보니 피보나치 수열과 같다는 것을 알게 되었다. 25 | -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/yeahLim/Main.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.io.*; 3 | 4 | public class Main { 5 | public static void main(String[] args) throws IOException { 6 | 7 | /* 입력 및 변수 초기화 */ 8 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | int n = Integer.parseInt(br.readLine()); 10 | int[] dp = new int[n+2]; 11 | 12 | /* dp : 2xn의 사각형 방법 구하기 */ 13 | dp[1] = 1; 14 | dp[2] = 2; 15 | for(int i=3; i<=n; i++) { 16 | dp[i] = (dp[i-2] + dp[i-1]) % 10007; 17 | } 18 | 19 | /* 출력 */ 20 | System.out.println(dp[n]); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /BOJ/[11726] 2xn 타일링/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [11726] 2xn 타일링 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | /* dp : 2xn의 사각형 방법 구하기 */ 11 | dp[1] = 1; 12 | dp[2] = 2; 13 | for(int i=3; i<=n; i++) { 14 | dp[i] = (dp[i-2] + dp[i-1]) % 10007; 15 | } 16 | ``` 17 | 18 | - 초기값을 설정하고, dp를 이용하여 풀었다. 19 | 20 | ## :black_nib: **Review** 21 | 22 | - 숫자 하나만 입력 받는 것이라 원래 Scanner를 이용하여 풀었는데, BufferedReader로 채점해보니 약 2배정도 빨라져서 br로 수정하였다. 23 | -------------------------------------------------------------------------------- /BOJ/[12100] 2048 (Easy)/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [12100] 2048 (Easy) 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 스택, 백트래킹 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void move(int[][] movedMap, int count) { 11 | if (count == 5) { 12 | return; 13 | } 14 | 15 | for (int m = 0; m < 4; m++) { 16 | move(moveMap(movedMap, m), count + 1); 17 | } 18 | } 19 | ``` 20 | 21 | - 백트래킹으로 5번까지 이동할 방향을 정하고 이동한다. 22 | 23 | ```java 24 | private static int[][] moveMap(int[][] target, int move) { 25 | Stack numbers; 26 | int[][] movedMap = new int[N][N]; 27 | boolean isPlus; 28 | int number; 29 | 30 | ... 31 | } 32 | ``` 33 | 34 | - 스택을 이용해 이동하면서 합쳐지는 숫자들을 처리한다. 35 | - 또한 boolean 값으로 합쳐진 숫자들이 다시 합쳐지지 않도록 한다. 36 | 37 | ## :black_nib: **Review** 38 | - 해당 게임은 예전에도 몇번 해본 적이 있어서 잘 알고 있었고, 어떻게 하면 최대 수가 나올 수가 있을지 정해진 공식이 있는 게 아니라고 생각해서 결국 다 해보는 수밖에 없다고 판단했다. 39 | - 이럴 때는 백트래킹 방식으로 각 이동 시의 상태를 함수의 인자로 전달해주면서 모든 경우를 돌려봐야했고, 숫자 합치기는 스택을 이용해서 구현해보았다. 40 | - 구현 문제는 가닥만 얼추 잡으면 구현하는데서는 많이 막히지 않는 것 같다. 시간을 좀 더 줄여볼 수 있도록 하자. -------------------------------------------------------------------------------- /BOJ/[1238] 파티/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [1238] 파티 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 다익스트라 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int i = 0; i < M; i++) { 11 | st = new StringTokenizer(br.readLine()); 12 | int v1 = Integer.parseInt(st.nextToken()); 13 | int v2 = Integer.parseInt(st.nextToken()); 14 | int w = Integer.parseInt(st.nextToken()); 15 | 16 | map[v1].add(new Road(v2, w)); 17 | mapReverse[v2].add(new Road(v1, w)); 18 | } 19 | 20 | dist = getShortestPath(map); 21 | distReverse = getShortestPath(mapReverse); 22 | ``` 23 | 24 | - X좌표에서 모든 지점으로 가는 최단 거리는 기본 다익스트라를 사용해 구한다. 25 | - 모든 지점에서 X좌표로 가는 최단 거리를 구하기위해선 경로의 시작과 끝점을 반대로 저장하여 다익스트라를 사용한다. 26 | 27 | ## :black_nib: **Review** 28 | 29 | - 다익스트라는 어떤 지점을 시작점으로 모든 좌표의 최단거리를 구하는 것이라 X좌표로 가는 길의 경로를 구하는 좋은 방법이 떠오르지 않아 블로그를 참고했다. 30 | - 경로를 반대로 저장하면 해결되는 문제로 간단하지만 내가 생각하긴 어려운 문제였다. -------------------------------------------------------------------------------- /BOJ/[1238] 파티/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [1238] 파티 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 다익스트라 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int index = 0; index < M; index++) { 11 | info = br.readLine().split(" "); 12 | 13 | int a = Integer.parseInt(info[0]) - 1; 14 | int b = Integer.parseInt(info[1]) - 1; 15 | int s = Integer.parseInt(info[2]); 16 | 17 | roadInfo.get(a).add(new Node(b, s)); 18 | reverseRoadInfo.get(b).add(new Node(a, s)); 19 | } 20 | ``` 21 | 22 | - 각 점에서 파티 마을까지의 최단 거리를 N번의 다익스트라가 아닌, 1번의 다익스트라로 구하기 위해 주어진 이동 정보를 반대로 저장한다. 23 | 24 | ## :black_nib: **Review** 25 | 26 | - 처음 아이디어는, 모든 점에서 다익스트라를 돌린 후, (각 점 -> 파티 마을 + 파티 마을 -> 각 점) 중 최댓값을 찾으려 했다. 27 | - 하지만 4%에서 틀렸습니다가 떴다.. 28 | - 게시판을 참고하니, 다익스트라 2번만으로 해결이 가능했다. 파티 마을을 시작점으로 하는 다익스트라 1번과, 주어진 이동정보를 반대로 한 후, 파티 마을을 시작점으로 하는 다익스트라 1번을 수행한다. 29 | - 이동정보를 반대로 하고, 파티 마을을 시작점으로 하게 되면, 각 점으로부터 파티 마을까지 가는 최단 거리를 구할 수 있게 되기 때문이다. -------------------------------------------------------------------------------- /BOJ/[1238] 파티/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [1238] 파티 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 플로이드워샬 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int k = 1; k <= n; k++) { 11 | for (int i = 1; i <= n; i++) { 12 | for (int j = 1; j <= n; j++) { 13 | dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]); 14 | } 15 | } 16 | } 17 | 18 | for (int i = 1; i <= n; i++) { 19 | answer = Math.max(dist[i][x] + dist[x][i], answer); 20 | } 21 | ``` 22 | 23 | - 플로이드워샬로 최소 시간을 각각 구한 다음에 각 학생이 파티를 하는 학생에 집에 가고 오는 거리가 제일 큰 학생의 시간을 출력 24 | 25 | ## :black_nib: **Review** 26 | 27 | - n의 최대값이 1000이어서, '''O(n^3)'''인 플로이드워샬을 사용할 수 있었다. -------------------------------------------------------------------------------- /BOJ/[13549] 숨바꼭질 3/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [13549] 숨바꼭질 3 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int cur = positions.poll(); 11 | // X-1 이동 12 | int back = cur - 1; 13 | // X+1 이동 14 | int go = cur + 1; 15 | 16 | if (back > 0) { 17 | if(warp(back, visited, positions)) { 18 | return time; 19 | } 20 | } 21 | 22 | if (go <= 100000) { 23 | if(warp(go, visited, positions)) { 24 | return time; 25 | } 26 | } 27 | ``` 28 | 29 | - 뒤로 한 칸, 앞으로 한 칸 이동하고 순간 이동할 수 있는 칸에 대해서 처리한다. 30 | 31 | ## :black_nib: **Review** 32 | 33 | - 좌표의 최대값을 정하는데 어려웠다. 34 | - 십만이상까지 가서 뒤로 갔을때 더 적은 시간이 걸리지 않을까라고 생각했는데 그런 경우가 없었다. 그래서 최대값을 십만으로 잡았다. 35 | -------------------------------------------------------------------------------- /BOJ/[13549] 숨바꼭질 3/ksg2388/Main.js: -------------------------------------------------------------------------------- 1 | const [n, k] = require('fs') 2 | .readFileSync('/dev/stdin') 3 | .toString() 4 | .trim() 5 | .split(' ') 6 | .map(Number); 7 | 8 | const position = []; 9 | const visited = Array.from({ length: 100001 }, () => 0); 10 | position.push([n, 0]); 11 | visited[n] = true; 12 | 13 | while (position.length) { 14 | let [p, dist] = position.shift(); 15 | 16 | if (p === k) { 17 | console.log(dist); 18 | break; 19 | } 20 | 21 | // 순간 이동 22 | if (p * 2 <= 100000 && !visited[p * 2]) { 23 | position.unshift([p * 2, dist]); 24 | visited[p * 2] = true; 25 | } 26 | 27 | // 이동 28 | if (p + 1 <= 100000 && !visited[p + 1]) { 29 | position.push([p + 1, dist + 1]); 30 | visited[p + 1] = true; 31 | } 32 | if (p - 1 >= 0 && !visited[p - 1]) { 33 | position.push([p - 1, dist + 1]); 34 | visited[p - 1] = true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /BOJ/[13549] 숨바꼭질 3/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [13549] 숨바꼭질 3 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | // 순간 이동 11 | if (p * 2 <= 100000 && !visited[p * 2]) { 12 | position.unshift([p * 2, dist]); 13 | visited[p * 2] = true; 14 | } 15 | 16 | // 이동 17 | if (p + 1 <= 100000 && !visited[p + 1]) { 18 | position.push([p + 1, dist + 1]); 19 | visited[p + 1] = true; 20 | } 21 | if (p - 1 >= 0 && !visited[p - 1]) { 22 | position.push([p - 1, dist + 1]); 23 | visited[p - 1] = true; 24 | } 25 | ``` 26 | 27 | - 순간이동을 하는 경우는 시간이 들지 않기 때문에 배열의 가장 앞에 삽입해준다. 28 | - 이동을 하는 경우는 현재 시간 + 1 값을 한 후 배열에 넣어준다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 순간이동 처리를 어떻게 할 것인지가 중요한 문제였다. 33 | - BFS를 이용하여 간단하게 해결할 수 있었다. 34 | -------------------------------------------------------------------------------- /BOJ/[14500] 테트로미노/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [14500] 테트로미노 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static int placeTetromino(List squares, int x, int y) { 11 | int sum = 0; 12 | for (Node square : squares) { 13 | int nx = square.x + x; 14 | int ny = square.y + y; 15 | 16 | if (!isIn(nx, ny)) { 17 | return -1; 18 | } 19 | sum += map[nx][ny]; 20 | } 21 | return sum; 22 | } 23 | ``` 24 | 25 | - 특정 테트로미노의 좌표 모음과 시작 좌표를 받아, 해당 위치에 테트로미노를 놓았을 경우의 영역 숫자의 합을 반환한다. 26 | 27 | ## :black_nib: **Review** 28 | - 모든 경우의 수를 다 구해두고, 하나씩 확인해보는 방식으로 구현했다. 29 | - DFS 방식으로 메모리 사용량을 줄일 방법도 있다는 것을 알게 됐다. -------------------------------------------------------------------------------- /BOJ/[14500] 테트로미노/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [14500] 테트로미노 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 브루트포스 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void checkA(int i) { 11 | for (int j = 0; j < M; j++) { 12 | sum = arr[i][j] + arr[i][j + 1] + arr[i + 1][j] + arr[i + 1][j + 1]; 13 | if (sum >= result) { 14 | result = sum; 15 | } 16 | } 17 | } 18 | ``` 19 | - 테트리스 모양 별로 모든 경우의 수를 구현하였다. 20 | - 현재까지의 최대값과 비교하여 최대값을 갱신한다 21 | 22 | 23 | ## :black_nib: **Review** 24 | - 구현외의 다른 방법으로 풀고 싶었으나, 풀지 못하였다. 25 | - 오목한 모양의 테트리스를 제외하고 dfs 방식으로 풀 수 있다는 것을 알았다. 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /BOJ/[14500] 테트로미노/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 브루트포스 4 | 5 | ## 중요 구현 로직 및 설명 6 | 7 | 나올 수 있는 모든 경우의 수를 계산하여 배열을 돌면서 체크 8 | 9 | 각각의 도형이 나올 수 있는 경우의 수 19가지를 모두 체크해보고 기존의 최대값보다 큰 경우 갱신 10 | image 11 | 배열을 돌면서 모든 테트로미노의 경우의 수를 확인해본다. 12 | 13 | ## 풀이 후기 14 | 15 | 처음에 문제를 제대로 읽지 않고 도형을 뒤집을 수 있다는 걸 모르고 문제를 풀어서 시간이 엄청 오래걸렸는데 다음부터는 이런 실수를 하지 않도록 문제를 제대로 읽고 풀어야겠다... 16 | -------------------------------------------------------------------------------- /BOJ/[15565] 귀여운 라이언/SUbbb/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.*; 5 | 6 | public class Main { 7 | public static void main(String[] args) throws IOException { 8 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | String[] info = br.readLine().split(" "); 10 | 11 | int N = Integer.parseInt(info[0]); 12 | int K = Integer.parseInt(info[1]); 13 | 14 | int[] dolls = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray(); 15 | 16 | int start = 0; 17 | int end = 0; 18 | int minSet = N + 1; 19 | int ryan = 0; 20 | 21 | while (end < N) { 22 | if (dolls[end++] == 1) { 23 | ryan++; 24 | } 25 | 26 | while (ryan == K) { 27 | // 정답 갱신 28 | minSet = Math.min(minSet, end - start); 29 | 30 | // start 옮기기 31 | if (dolls[start++] == 1) { 32 | ryan--; 33 | } 34 | } 35 | } 36 | 37 | if (minSet == N + 1) { 38 | minSet = -1; 39 | } 40 | 41 | System.out.println(minSet); 42 | } 43 | } -------------------------------------------------------------------------------- /BOJ/[15565] 귀여운 라이언/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [15565] 귀여운 라이언 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 두 포인터, 슬라이딩 윈도우 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | while (end < N) { 11 | if (dolls[end++] == 1) { 12 | ryan++; 13 | } 14 | 15 | while (ryan == K) { 16 | // 정답 갱신 17 | minSet = Math.min(minSet, end - start); 18 | 19 | // start 옮기기 20 | if (dolls[start++] == 1) { 21 | ryan--; 22 | } 23 | } 24 | } 25 | ``` 26 | 27 | - 라이언 개수를 계속 추적하면서, start와 end 인덱스를 변경한다. 28 | 29 | ## :black_nib: **Review** 30 | - 두 포인터 문제는 항상 구현하다가 한 번 꼬이면 시간이 많이 걸리는 것 같다. 31 | - 그래서 처음에는 더럽게 풀었다가 ... 조금씩 수정했다. -------------------------------------------------------------------------------- /BOJ/[1563] 개근상/jungu12/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.Arrays; 5 | 6 | public class Main { 7 | public static void main(String[] args) throws IOException { 8 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | 10 | int N = Integer.parseInt(br.readLine()); 11 | int[][][] dp = new int[N + 1][2][3]; // 날짜, 지각 횟수, 연속으로 결석한 횟수 12 | dp[1][0][0] = 1; 13 | dp[1][0][1] = 1; 14 | dp[1][1][0] = 1; 15 | 16 | for (int i = 2; i <= N; i++) { 17 | dp[i][0][0] = (dp[i - 1][0][0] + dp[i - 1][0][1] + dp[i - 1][0][2]) % 1000000; 18 | dp[i][0][1] = dp[i - 1][0][0]; 19 | dp[i][0][2] = dp[i - 1][0][1]; 20 | dp[i][1][0] = (Arrays.stream(dp[i - 1][0]).sum() + Arrays.stream(dp[i - 1][1]).sum()) % 1000000; 21 | dp[i][1][1] = dp[i - 1][1][0]; 22 | dp[i][1][2] = dp[i - 1][1][1]; 23 | } 24 | 25 | System.out.println((Arrays.stream(dp[N][0]).sum() + Arrays.stream(dp[N][1]).sum()) % 1000000); 26 | } 27 | } -------------------------------------------------------------------------------- /BOJ/[16236] 아기 상어/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [16236] 아기 상어 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 그래프 이론, 그래프 탐색, BFS, 시뮬레이션 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```c++ 10 | int seconds = 0; 11 | // 물고기 탐색 -> 자신보다 작은 물고기를 찾으면, 거리 계산 12 | // 거리 계산과 동시에 거리가 가장 가까운 물고기를 찾기 13 | while (true) { 14 | findFish(); 15 | 16 | if (minFish == null) { 17 | break; 18 | } 19 | 20 | // 상어 이동 21 | map[minFish[0]][minFish[1]] = 0; 22 | sharkX = minFish[0]; 23 | sharkY = minFish[1]; 24 | 25 | // 시간 증가 26 | seconds += minMove; 27 | 28 | // 상어 먹은 횟수 비교해서, 상어 크기 증가 29 | if (++eatCount == sharkSize) { 30 | sharkSize++; 31 | eatCount = 0; 32 | } 33 | } 34 | ``` 35 | 36 | - 주어진 로직을 그대로 실행한다. 37 | - 거리가 가장 가까운 물고기를 구하기 위해 BFS를 사용했다. 38 | 39 | ## :black_nib: **Review** 40 | 41 | - 생각보다 간단한 문제여서 구현은 금방했는데, 메모리랑 시간 사용량이 다른 코드에 많이 컸다. 42 | - 우선순위 큐를 사용해서 풀이한 코드들이었는데, 아무래도 나는 매번 BFS를 수행해서 많이 사용하는 것 같다. -------------------------------------------------------------------------------- /BOJ/[16472] 고냥이/HyeW/Cat.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.*; 3 | 4 | public class Cat { 5 | static int N; 6 | static String meow; 7 | static int max = 0; 8 | static Map chars; 9 | 10 | public static void main(String[] args) throws IOException { 11 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 12 | 13 | N = Integer.parseInt(br.readLine()); 14 | meow = br.readLine(); 15 | chars = new HashMap<>(); 16 | 17 | int start = 0; 18 | for(int i = 0; i < meow.length(); i++) { 19 | 20 | chars.put(meow.charAt(i), chars.getOrDefault(meow.charAt(i), 0)+1); 21 | 22 | while(chars.size() > N) { 23 | char start_char = meow.charAt(start); 24 | 25 | chars.put(start_char, chars.get(start_char)-1); 26 | if(chars.get(start_char) == 0) 27 | chars.remove(start_char); 28 | 29 | start++; 30 | } 31 | 32 | max = Math.max(max, i - start + 1); 33 | } 34 | 35 | System.out.println(max); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /BOJ/[16472] 고냥이/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [16472] 고냥이 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 투 포인터 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int start = 0; 11 | for(int i = 0; i < meow.length(); i++) { 12 | 13 | chars.put(meow.charAt(i), chars.getOrDefault(meow.charAt(i), 0)+1); 14 | 15 | while(chars.size() > N) { 16 | char start_char = meow.charAt(start); 17 | 18 | chars.put(start_char, chars.get(start_char)-1); 19 | if(chars.get(start_char) == 0) 20 | chars.remove(start_char); 21 | 22 | start++; 23 | } 24 | 25 | max = Math.max(max, i - start + 1); 26 | } 27 | ``` 28 | 문자와 문자의 개수를 HashMap에 저장한다. 문자의 종류(Map의 크기)가 주어진 N보다 커지면 start인덱스를 사용해 문자의 종류가 줄어들 때까지 끝에서 문자를 하나씩 제거한다.
29 | 30 | ## :black_nib: **Review** 31 | - 포인터 두개를 사용해서 문제를 해결한 적이 많은데 이를 투 포인터 알고리즘이라고 부른다는 것을 이 문제를 통해 알게되었다. 32 | - 특정 문자의 개수를 알고 있어야 해서 key-value로 자료를 저장할 수 있는 Map을 사용했다. -------------------------------------------------------------------------------- /BOJ/[16472] 고냥이/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [16472] 고냥이 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 투 포인터 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void findMaxLen() { 11 | for (int start = 0; start < catStr.length() - maxLen; start++) { 12 | Set typeNum = new HashSet<>(); 13 | int end = start; 14 | while (true) { 15 | typeNum.add(catStr.charAt(end)); 16 | if(typeNum.size() > N) { 17 | end --; 18 | break; 19 | } 20 | end++; 21 | if (end == catStr.length()) { 22 | end--; 23 | break; 24 | } 25 | } 26 | int len = end - start + 1; 27 | if (len > maxLen) { 28 | maxLen = len; 29 | } 30 | } 31 | } 32 | ``` 33 | - Set에 새로운 문자를 check할 때 마다 add를 해주어 사용된 알파벳 종류를 관리한다. 34 | - 알파벳 최대 종류를 넘거나, 문자열을 끝까지 다 확인했다면, 이전까지의 maxLen과 비교하여 값을 갱신해준다. 35 | 36 | 37 | ## :black_nib: **Review** 38 | - 투 포인터를 사용하여 어렵지 않게 구현 할 수 있는 문제였다. 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /BOJ/[16472] 고냥이/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [16472] 고냥이 - Java 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 투 포인터 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | # [16472] 고냥이 - Java 11 | 12 | ## :pushpin: **Algorithm** 13 | 14 | 투 포인터 15 | 16 | ## :round_pushpin: **Logic** 17 | 18 | ```java 19 | while(right < str.length()) { 20 | 21 | 22 | alphCnt[str.charAt(right) - 'a']++; 23 | 24 | if(alphCnt[str.charAt(right) - 'a'] == 1) { 25 | count++; 26 | } 27 | 28 | while(count > n) { 29 | alphCnt[str.charAt(left) - 'a']--; 30 | if(alphCnt[str.charAt(left) - 'a'] == 0) { 31 | count--; 32 | } 33 | left++; 34 | } 35 | 36 | right++; 37 | 38 | maxLen = (maxLen < right - left) ? right - left : maxLen; 39 | } 40 | ``` 41 | 42 | - left는 기준이되는 가장 첫번째 문자열을 가리키고, right는 left의 오른쪽 문자열을 가리킨다. 43 | - 알파벳의 종류가 n보다 큰 경우, while문을 통해 left의 인덱스를 하나씩 증가시키면서, 0이 될때까지 문자를 하나씩 지워준다. 44 | 45 | ## :black_nib: **Review** 46 | - 처음에는 알파벳의 종류를 세는 배열을 매번 초기화시켜서 시간초과가 났다. 투포인트 방법을 배워서 좋았다. 47 | -------------------------------------------------------------------------------- /BOJ/[17070] 파이프 옮기기 1/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | DP를 이용해 구현 4 | 5 | ## 중요 구현 로직 및 설명 6 | 1. 가로, 대각선, 세로 모양을 기준으로 3개의 형태의 값들의 배열을 만든다. 7 | 2. 먼저 최상단의 가로 모양 값들을 초기화한다. 8 | 3. 벽을 만난 경우는 0을 넣고 초기화를 멈춘다. (더 이상 갈 수 없기 때문) 9 | 4. 이후 나머지 범위의 값을 초기화 한다. 10 | 5. 대각선의 경우는 위와 왼쪽의 경우도 비어있어야하기때문에 한번 더 검사해준다. 11 | 12 | ```java 13 | for (int i = 1; i < n; i++) { 14 | for (int j = 2; j < n; j++) { 15 | // 벽인 경우 16 | if (map[i][j] == 1) { 17 | continue; 18 | } 19 | // 가로 초기화 20 | dp[i][j][0] = dp[i][j-1][0] + dp[i][j-1][1]; 21 | // 대각선 초기화 22 | if (map[i - 1][j] != 1 && map[i][j - 1] != 1) { 23 | dp[i][j][1] = dp[i-1][j-1][0] + dp[i-1][j-1][1] + dp[i-1][j-1][2]; 24 | } 25 | // 세로 초기화 26 | dp[i][j][2] = dp[i-1][j][1] + dp[i-1][j][2]; 27 | } 28 | } 29 | ``` 30 | 이렇게 초기화를 다 시켜두고 마지막에 (n, n)의 값에 올 수 있는 3가지 모양의 값들을 더해서 결과값을 출력한다. 31 | 32 | ## 풀이 후기 33 | 34 | dp를 이용하는 문제는 역시 쉽지 않았다. 35 | -------------------------------------------------------------------------------- /BOJ/[17136] 색종이 붙이기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [17136] 색종이 붙이기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 브루트 포스, 백트래킹 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 1. (0, 0)에서 시작해서 (9, 9)까지 이동하면서 색종이를 붙일 수 있는 경우를 확인한다. 10 | 2. 색종이를 붙일 수 있는 경우 큰 색종이부터 내림차순으로 확인해보면서 모든 경우를 다 확인해본다. 11 | 12 | ```java 13 | static int[] confetti = { 5, 5, 5, 5, 5 }; 14 | 15 | // 큰 색종이부터 순서대로 붙일 수 있나 확인 16 | for (int i = 4; i >= 0; i--) { 17 | if (checkConfetti(x, y, i + 1, map)) { 18 | int[][] newMap = new int[10][10]; 19 | copyArray(newMap, map); 20 | if (confetti[i] == 0) { 21 | return; 22 | } 23 | confetti[i]--; 24 | glueConfetti(x, y + i + 1, count + 1, paste(x, y, i + 1, newMap)); 25 | confetti[i]++; 26 | } 27 | } 28 | ``` 29 | 30 | - 색종이의 개수 배열의 값들을 각각 5로 초기화 시켜둔다. 31 | - 색종이를 붙일 수 있는 경우 복사한 배열에 색종이를 붙인 후 그 다음 좌표로 이동하여 계속 확인한다. 32 | - 도중 색종이의 개수가 남지 않은 경우는 거기서 종료한다. 33 | 34 | ## :black_nib: **Review** 35 | 36 | - 쉽게 구현할 수 있는 방법이 있지 않을까 많이 고민을 해봤지만 결국 모든 경우를 다 확인해보는 방법으로 구현했다. 37 | - 2차원 배열의 인덱스를 다루는 방법이 많이 익숙해졌다. 38 | -------------------------------------------------------------------------------- /BOJ/[17136] 색종이 붙이기/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [17136] 색종이 붙이기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 브루트 포스, 백트래킹 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 10 | - 백트래킹으로 모든 보드에서 색종이를 붙일 수 있는 공간을 찾는다. 11 | 12 | ```java 13 | // 색종이를 붙일 수 있는 공간일 경우 14 | if(board[x][y] == 1) { 15 | for(int i=4; i>=0; i--) { 16 | if(paper[i] == 0 || !searchSize(x, y, i)) continue; 17 | attachPaper(x, y, i, 0); // 색종이 붙이기 18 | paper[i]--; 19 | searchBoard(x, y+1, total+1); 20 | attachPaper(x, y, i, 1); // 색종이 떼기 21 | paper[i]++; 22 | } 23 | } 24 | ``` 25 | 26 | - 색종이를 붙일 수 있는 공간이라면, searchSize()를 통해 어떤 사이즈의 색종이를 붙일 수 있는지 확인한다. 27 | - 5x5부터 1x1까지의 색종이를 하나씩 대입한다. 28 | - 사이즈를 찾고, 그 사이즈의 색종이가 남아 있다면, 색종이를 붙인다. 29 | - 위를 반복해서, 색종이의 최소 개수를 구한다. 30 | 31 | ## :black_nib: **Review** 32 | - 백트래킹과 dfs의 근본적인 차이점을 알 수 있었다. dfs는 그래프 기반의 알고리즘이고 백트래킹은 그래프와는 무관하다. 33 | - 배열을 복사하지않고, 색종이를 붙이고 떼는 방법을 사용하는 것이 더 효율이 좋은 것 같다. -------------------------------------------------------------------------------- /BOJ/[17144] 미세먼지 안녕!/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [17144] 미세먼지 안녕! 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 시뮬레이션 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 문제에서 요구하는 동작은 2가지이다.
10 | 1. 미세먼지 확산하기 11 | 2. 공기청정기 작동하기 12 | 13 | ```java 14 | while(T-- > 0) { 15 | spreadDusts(); 16 | runAirCondition(); 17 | } 18 | ``` 19 | 20 | ```java 21 | private static void spreadDusts() 22 | ``` 23 | 모든 배열을 확인하면서 0이상이면 4방탐색을 통해 미세먼지를 확산시킨다.
24 | 25 | ```java 26 | private static void runAirCondition() 27 | ``` 28 | 인덱스로 접근하여 미세먼지를 하나하나 이동시켜준다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 코드트리에서 푼 문제보다 너무 간단한 구현 문제였다. 33 | - 그런데 공기청정기를 가동시킬 때 인덱스 범위를 잘못 설정해서 살짝 시간이 걸렸다. -------------------------------------------------------------------------------- /BOJ/[17144] 미세먼지 안녕!/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [17144] 미세먼지 안녕! 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 시뮬레이션 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static int goodByeDust() { 11 | while(T-- > 0) { 12 | spreadDust(); 13 | runCleaner(); 14 | } 15 | return countDust(); 16 | } 17 | ``` 18 | 19 | - 코드는 먼지를 확산시키고, 공기청정기를 동작시킨다. 정해진 시간이 경과한 후, 전체 미세 먼지를 반환한다. 20 | 21 | ```java 22 | private static void spreadDust() {...} 23 | ``` 24 | 25 | - 미세 먼지를 확산시킨다. 26 | - 이때 업데이트할 미세 먼지 정보를 `int[][] tmp` 에 저장하고, 확산이 끝난 이후 `room[][]` 을 업데이트한다. 27 | 28 | ```java 29 | private static void runCleaner() {...} 30 | ``` 31 | 32 | - 공기 청정기의 바람 방향을 따라 순차적으로 미세 먼지를 이동시킨다. 33 | - 공기 청정기 바로 앞 좌표는 항상 `0` 으로 업데이트한다. 34 | 35 | ## :black_nib: **Review** 36 | 37 | - 이전에는 큐를 이용해서 미세먼지 정보를 저장했었는데, 메모리를 너무 많이 잡아먹었다. 38 | - 따라서 배열을 탐색해서 미세먼지를 찾도록 수정해서 메모리 사용량을 줄일 수 있었다. 39 | -------------------------------------------------------------------------------- /BOJ/[17144] 미세먼지 안녕!/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [17144] 미세먼지 안녕! 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 시뮬레이션 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | /* t초 동안 실행 */ 11 | while(t-- > 0) { 12 | spreadDust(); 13 | purifyAir(); 14 | } 15 | ``` 16 | 17 | - 1초 동안 먼지가 퍼지고, 공기청정기가 작동된다. 따라서 t초동안 spreadDust()와 purifyAir()을 실행한다. 18 | 19 | ```java 20 | private static int[][] cloneDust(int[][] cpDust) {...} 21 | ``` 22 | 23 | - 미세먼지를 순회하면서 미세먼지를 하나하나 퍼뜨린다. 24 | - 퍼진 미세먼지를 새 배열인 `int[][] newDust` 에 누적시킨다. 25 | - 확산이 끝난 이후 `dust[][]`에 복사한다. 26 | 27 | ```java 28 | private static void purifyAir() {...} 29 | ``` 30 | 31 | - `int[][] newDust`에 `dust[][]`를 복사한다. -`dust[][]`에 이동된 미세먼지의 값으로 업데이트한다. 32 | - 공기 청정기 바로 앞 좌표는 항상 `0` 으로 업데이트한다. 33 | 34 | ## :black_nib: **Review** 35 | 36 | - 문제 풀기 전에, 미리 수기로 로직을 다 작성하고 진행했더니 손쉽게 풀렸다. 37 | - 알고리즘을 풀 때 주의할 점 : 1턴만 돌릴때랑, 여러 턴을 돌릴 때 정답이 달라지지 않도록 로직을 짜야한다. 38 | -------------------------------------------------------------------------------- /BOJ/[17404] RGB거리 2/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [17404] RGB거리 2 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | /* DP : 집 색칠할 수 있는 모든 비용 구하기 */ 11 | for (int start = 0; start < 3; start++) { 12 | for (int end = 0; end < 3; end++) { 13 | dp[start][end][seq] = Math.min(dp[start][(end+1)%3][seq - 1], dp[start][(end+2)%3][seq - 1]) + cost[end]; 14 | } 15 | } 16 | ``` 17 | 18 | - dp[시작 색][끝 색][순서] 19 | 20 | ```java 21 | /* 최소 비용 구하기 */ 22 | int minCost = Integer.MAX_VALUE; 23 | for (int start = 0; start < 3; start++) { 24 | for (int end = 0; end < 3; end++) { 25 | //시작 색, 끝 색 같을 경우 26 | if (start == end) { 27 | continue; 28 | } 29 | 30 | minCost = Math.min(dp[start][end][n], minCost); 31 | } 32 | } 33 | ``` 34 | - 모든 집의 비용의 최소값 = min(마지막이 빨강색인 집의 최소값, 마지막이 파랑색인 집의 최소값, 마지막이 초록색인 집의 최소값) 35 | 36 | ## :black_nib: **Review** 37 | 38 | - dp를 3차원으로 푼 것은 처음이다. dp와 더 깊은 관계를 맺는 시간이었다.. 39 | -------------------------------------------------------------------------------- /BOJ/[17406] 배열 돌리기 4/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [17406] 배열 돌리기 4 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 순열, 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void makeOrders(int[] order, boolean[] isSelected, int size) { 11 | if (size == K) { 12 | copy(); 13 | operateByOrders(order); 14 | min = Math.min(min, computeRowSum()); 15 | return; 16 | } 17 | 18 | for (int i = 0; i < K; i++) { 19 | if (isSelected[i]) { 20 | continue; 21 | } 22 | order[size] = i; 23 | isSelected[i] = true; 24 | makeOrders(order, isSelected, size + 1); 25 | isSelected[i] = false; 26 | } 27 | } 28 | ``` 29 | 30 | - 가능한 모든 연산 순서를 순열로서 구한다. 31 | 32 | ## :black_nib: **Review** 33 | - 로직은 생각보다 금방 짰다. 순열을 이용해 가능한 모든 연산 순서를 생성한 후, 최소값을 찾았다. 34 | - 하지만 배열에 대한 초기화와 복사를 수행하지 않아서, 아까운 시간을 허비했다. 35 | - 얕은 복사와 깊은 복사 .. 명심 -------------------------------------------------------------------------------- /BOJ/[17406] 배열 돌리기 4/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 순열을 사용 4 | 5 | ## 중요 구현 로직 및 설명 6 | 7 | 순열을 이용해 가능한 배열 돌리기 방법 중 각 행의 값이 최소가 되는 값을 찾음 8 | 9 | 1. 배열을 초기화 하고 각 회전 연산들을 저장해둔다. 10 | 2. 저장해둔 회전 연산들을 순열을 이용해 최소 값이 되는 경우를 찾는다. 11 | ``` java 12 | if (depth == k) { 13 | // 배열 돌리기 후 비교 14 | int[][] temp = new int[n][m]; 15 | for (int i = 0; i < n; ++i) { 16 | for (int j = 0; j < m; ++j) { 17 | temp[i][j] = arr[i][j]; 18 | } 19 | } 20 | 21 | for (int i = 0; i < k; ++i) { 22 | String[] cmd = command[idx.get(i)].split(" "); 23 | int r = Integer.parseInt(cmd[0]); 24 | int c = Integer.parseInt(cmd[1]); 25 | int s = Integer.parseInt(cmd[2]); 26 | arr = rotateArray(r, c, s); 27 | } 28 | // 최소값 구하기 29 | for (int[] a : arr) { 30 | int sum = 0; 31 | for (int b: a) { 32 | sum += b; 33 | } 34 | if (sum < result) { 35 | result = sum; 36 | } 37 | } 38 | arr = temp; 39 | return; 40 | } 41 | ``` 42 | ## 풀이 후기 43 | 44 | 코드가 길어지니 확실히 메소드를 부분별로 나누어 하는 방법이 도움이 많이 되었다. -------------------------------------------------------------------------------- /BOJ/[1759] 암호 만들기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 정렬 후 DFS를 이용 3 | 4 | ## 중요 구현 로직 및 설명 5 | 6 | n은 이전에 탐색하던 마지막 자리를 기억하기 위해 사용 7 | code를 통해 암호를 저장 8 | depth는 문자열의 길이를 나타내기 위해 사용 9 | dfs를 이용해 탐색을하다가 depth 즉 문자의 길이가 L개와 같아질 경우 유효성을 검사하고 맞는 경우 리스트에 추가한다. 10 | 11 | ## 풀이 후기 12 | 풀고 난 후 다시 보니 코드를 더 줄일 수 있을 것 같아보인다. 그리고 입출력을 받을 때 좀 더 간결하게 할 수 있는 방법이 있을 것 같은데 찾아봐야겠다. 13 | 14 | -------------------------------------------------------------------------------- /BOJ/[1865] 웜홀/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [1865] 웜홀 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 벨만포드 알고리즘 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static boolean hasMinusCycle() { 11 | dis[1] = 0; 12 | 13 | for(int i = 1; i < N; i++) { 14 | for(int j = 1; j < road.length; j++) { 15 | for(edge next: road[j]) { 16 | if(dis[j] + next.time < dis[next.node]) { 17 | dis[next.node] = dis[j] + next.time; 18 | } 19 | } 20 | } 21 | } 22 | 23 | for(int j = 1; j < road.length; j++) { 24 | for(edge next: road[j]) { 25 | if(dis[j] + next.time < dis[next.node]) { 26 | return true; 27 | } 28 | } 29 | } 30 | return false; 31 | } 32 | ``` 33 | 34 | - 음수 사이클이 존재한다면 문제에서 찾고자 하는 조건을 만족하는 경우이다. 35 | - 음수 사이클이 생기는지 확인하여 생긴다면 true를 반환한다. 36 | 37 | ## :black_nib: **Review** 38 | 39 | - 벨만 포드 알고리즘에 대한 이해도가 부족하다.. 40 | -------------------------------------------------------------------------------- /BOJ/[1865] 웜홀/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [1865] 웜홀 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 벨만 포드 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | const bellmanFord = (edge) => { 11 | const n = edge.length; 12 | const INF = (edge.length - 1) * 10000; 13 | const dist = Array(n).fill(INF); 14 | dist[1] = 0; 15 | let isUpdated; 16 | for (let i = 0; i < n; i++) { 17 | isUpdated = false; 18 | for (let j = 1; j < n; j++) { 19 | for (const { to, distance } of edge[j]) { 20 | if (dist[to] > dist[j] + distance) { 21 | if (i === n - 1) return 'YES'; 22 | dist[to] = dist[j] + distance; 23 | isUpdated = true; 24 | } 25 | } 26 | } 27 | if (!isUpdated) return 'NO'; 28 | } 29 | }; 30 | ``` 31 | 32 | - 모든 정점을 돌면서 최단경로를 갱신하면서 음수 사이클이 있는지 존재한다. 33 | - 모든 정점을 다 검사한 후에 한번 더 갱신을 한 경우 갱신이 가능하다면 그 경우는 음수 사이클이 존재하는 경우이다. 34 | 35 | ## :black_nib: **Review** 36 | 37 | - 벨만 포드 알고리즘에 대해 잘 몰라서 답을 참고했다..ㅎ ㅎ 38 | - 이 문제는 기본 벨만포드 문제와 다르게 음수사이클이 존재 유무만 확인하면 되는 문제였기때문에 노드 간의 단절을 확인해줄 필요가 없었다. 39 | -------------------------------------------------------------------------------- /BOJ/[1890] 점프/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [1890] 점프 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int x = 0; x < N; x++) { 11 | for (int y = 0; y < N; y++) { 12 | int jump = map[x][y]; 13 | if (jump == 0) { 14 | continue; 15 | } 16 | 17 | // 오른쪽 18 | if (y + jump < N) { 19 | paths[x][y + jump] += paths[x][y]; 20 | } 21 | 22 | // 아래 23 | if (x + jump < N) { 24 | paths[x + jump][y] += paths[x][y]; 25 | } 26 | } 27 | } 28 | ``` 29 | 30 | - 점프할 수 있는 거리가 0이 아닌 칸들로부터, 오른쪽, 아래쪽으로 이동한다. 31 | - 점프가 가능하다면, 현재 좌표까지 올 수 있는 경우의 수를 더해준다. 32 | 33 | ## :black_nib: **Review** 34 | - 이전 정보를 사용하지 않고, ++로 경우의 수를 증가시켜주는 방식으로 구현했더니 메모리초과가 계속 발생했다. 35 | - 메모이제이션을 활용하는 것을 까먹지 말자... -------------------------------------------------------------------------------- /BOJ/[1890] 점프/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [1890] 점프 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static long countRoute() { 11 | long[][] dp = new long[N][N]; 12 | dp[0][0] = 1; 13 | for (int i = 0; i < N; i++) { 14 | for (int j = 0; j < N; j++) { 15 | if (dp[i][j] >= 1 && board[i][j] != 0) { 16 | if (i + board[i][j] < N) { 17 | dp[i + board[i][j]][j] += dp[i][j]; 18 | } 19 | if (j + board[i][j] < N) { 20 | dp[i][j + board[i][j]] += dp[i][j]; 21 | } 22 | } 23 | } 24 | } 25 | return dp[N-1][N-1]; 26 | } 27 | ``` 28 | - 시작 좌표에서 부터 갈 수 있는 좌표만 방문하며 경로 수를 갱신 해주는 DP방법으로 해결하였다. 29 | - DP[][] 2차원 배열에 해당 좌표까지 갈 수 있는 경로의 수를 저장하며 도착점 까지 움직인다. 30 | - DP 배열의 값이 0이라면 갈 수 없는 좌표이기에, task를 수행할 필요가 없다. 31 | - 최대 경로의 개수가 Integer의 범위를 넘어감으로 Long형으로 DP배열을 만들어 주었다. 32 | 33 | 34 | 35 | ## :black_nib: **Review** 36 | - 별 생각 없이 재귀로 문제를 풀려고 하였으나, 문제 조건에 '경로의 개수는 2^63-1보다 작거나 같다' 라는 조건이 있어 재귀로는 풀 수 없는 문제였다. 37 | - 조건에 맞는 자료형을 바로 고르지 못하였다. 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /BOJ/[1890] 점프/ksg2388/RAEDME.md: -------------------------------------------------------------------------------- 1 | # [1890] 점프 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 1. (0, 0)에서 시작해 오른쪽 아래쪽으로 점프하면서 갈 수 있는 경우의 수를 추가한다. 10 | 11 | ```java 12 | for (int i = 0; i < N; i++) { 13 | for (int j = 0; j < N; j++) { 14 | // 이 위치로 온 경우가 있는 경우 15 | if (dp[i][j] > 0) { 16 | if (i == N - 1 && j == N - 1) { 17 | break; 18 | } 19 | int num = map[i][j]; 20 | // 오른쪽으로 이동하는 경우 21 | if (j + num < N) { 22 | dp[i][j + num] += dp[i][j]; 23 | } 24 | // 아래로 이동하는 경우 25 | if (i + num < N) { 26 | dp[i + num][j] += dp[i][j]; 27 | } 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | ## :black_nib: **Review** 34 | 35 | - 계속해서 한 방향으로 쌓아가는 느낌의 문제는 DP를 이용하여 푸는 것이 익숙해졌다. 36 | -------------------------------------------------------------------------------- /BOJ/[1890] 점프/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [1890] 점프 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for(int i=0; i= priority(ex)) { 33 | if (stack.peek() == '(') { 34 | break; 35 | } 36 | sb.append(stack.pop()); 37 | } 38 | stack.add(ex); 39 | ``` 40 | 41 | - 연산자를 만나면, 현재 연산자보다 스택에 있는 연산자의 우선 순위가 같거나 높은 때까지 하나씩 빼준다. 42 | - 더 이상 없으면, 현재 연산자를 스택에 추가한다. 43 | 44 | ## :black_nib: **Review** 45 | 46 | - 스택의 느낌이 술술 났다. 하지만 조건식을 찾는 것이 매우매우 어려웠다는 점.. 47 | -------------------------------------------------------------------------------- /BOJ/[19237] 어른 상어/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [19237] 어른 상어 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int time = 0; 11 | while (sharks.size() > 1 && time <= 1000) { 12 | moveSharks(); 13 | decreaseSmells(); 14 | spreadSmells(); 15 | time++; 16 | } 17 | 18 | ``` 19 | 20 | - 로직의 순서는 다음과 같 21 | 다. 22 | - 상어들을 이동시킨다. 23 | - 이전의 냄새들을 1씩 감소시킨다. 24 | - 이동한 상어의 좌표에 냄새를 뿌린다. 25 | 26 | ```java 27 | // 상어가 위를 향할때 28 | if(shark.head == 1) { 29 | 30 | // 빈 공간이면 이동 31 | for(int i=1; i<=4; i++) { 32 | if(checkSpace(shark.direction[1][i], shark)) return; 33 | } 34 | 35 | // 자신의 냄새가 있는 공간이면 이동 36 | for(int i=1; i<=4; i++) { 37 | if(checkOwnSmell(shark.direction[1][i], shark)) return; 38 | } 39 | } 40 | ``` 41 | 42 | - 빈공간이 없을경우 자신의 냄새가 있는 공간으로 이동한다 43 | - 너무 힘들다 44 | 45 | ## :black_nib: **Review** 46 | 47 | - 너무 힘들어.. 하지만 나 배추가 아니기 때문에 포기하지 않는다!!!!!!!!!!!!!!!!!!!!!!!!! 48 | -------------------------------------------------------------------------------- /BOJ/[1932] 정수 삼각형/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [1932] 정수 삼각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 꼭지점 초기화 11 | maxCost.get(0)[0] = triangle.get(0)[0]; 12 | 13 | for (int i = 1; i < N; i++) { 14 | for (int j = 0; j <= i; j++) { 15 | //왼쪽 변일 경우 16 | if(j == 0) { 17 | maxCost.get(i)[j] = maxCost.get(i-1)[j]+triangle.get(i)[j]; 18 | continue; 19 | } 20 | //오른쪽 변일 경우 21 | if(j == i) { 22 | maxCost.get(i)[j] = maxCost.get(i-1)[j-1]+triangle.get(i)[j]; 23 | continue; 24 | } 25 | maxCost.get(i)[j] = Math.max(maxCost.get(i-1)[j], maxCost.get(i-1)[j-1]) 26 | +triangle.get(i)[j]; 27 | } 28 | } 29 | ``` 30 | 31 | 현재 지점에서 바로 윗 줄을 확인한다.
32 | 내가 선택할 수 있는 두가지 수 중 큰 값을 내가 취하면 된다.
33 | 이때 `maxCost`란 현재 지점을 포함한 최대 값을 저정한 DP배열을 이용하여 구한다. 34 | 35 | ## :black_nib: **Review** 36 | - 이정도 DP는 무리 없이 풀 수 있다! -------------------------------------------------------------------------------- /BOJ/[1932] 정수 삼각형/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [1932] 정수 삼각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | dp[0][0] = triangle[0][0]; 11 | 12 | for (int row = 1; row < N; row++) { 13 | // col == 0 14 | dp[row][0] = triangle[row][0] + dp[row - 1][0]; 15 | 16 | for (int col = 1; col < row; col++) { 17 | dp[row][col] = triangle[row][col] + Math.max(dp[row - 1][col - 1], dp[row - 1][col]); 18 | } 19 | 20 | // col == row 21 | dp[row][row] = triangle[row][row] + dp[row - 1][row - 1]; 22 | } 23 | ``` 24 | 25 | - 이전 행의 삼각형 숫자 중 현재 위치로 이동할 수 있는 값들에서 최댓값을 찾아 현재 행으로 더한다. 26 | 27 | ## :black_nib: **Review** 28 | 29 | - 매우 쉬운 형태의 DP! 30 | -------------------------------------------------------------------------------- /BOJ/[1932] 정수 삼각형/asever0318/Main_1932.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.StringTokenizer; 3 | 4 | public class Main { 5 | public static void main(String[] args) throws IOException { 6 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 7 | 8 | int N = Integer.parseInt(br.readLine()); 9 | int[] dp = new int[N]; 10 | int[][] triangle = new int[N][N]; 11 | 12 | for(int i = 0; i < N; i++) { 13 | StringTokenizer st = new StringTokenizer(br.readLine()); 14 | int j = 0; 15 | while(st.hasMoreTokens()) { 16 | triangle[i][j] = Integer.parseInt(st.nextToken()); 17 | j++; 18 | } 19 | } 20 | 21 | // 가장 마지막 레벨의 수로 dp 배열 초기화 22 | for(int i = 0; i < N; i++) { 23 | dp[i] = triangle[N-1][i]; 24 | } 25 | 26 | // 맨 밑단부터 위로 올라오기 27 | for(int i = N-2; i >= 0; i--) { 28 | for(int j = 0; j <= i; j++) { 29 | dp[j] = Math.max(dp[j] + triangle[i][j], dp[j+1] + triangle[i][j]); 30 | } 31 | } 32 | 33 | System.out.println(dp[0]); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /BOJ/[1932] 정수 삼각형/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [1932] 정수 삼각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int i = 1; i < N; i++) { 11 | dp[i][0] = dp[i - 1][0] + triangle[i][0]; 12 | dp[i][i] = dp[i - 1][i - 1] + triangle[i][i]; 13 | for (int j = 1; j < i; j++) { 14 | dp[i][j] = Math.max(dp[i - 1][j - 1], dp[i - 1][j]) + triangle[i][j]; 15 | } 16 | } 17 | ``` 18 | 19 | - 문제에서 '아래층에 있는 수는 현재 층에서 선택된 수의 대각선 왼쪽 또는 대각선 오른쪽에 있는 것 중에서만 선택할 수 있다.'라고 명시 되어 있다. 20 | - 이를 '위층에 있는 대각선 왼쪽 또는 대각선 오른쪽 수 중 큰 수를 선택할 수 있다.'로 해석 가능하다. 21 | 22 | ## :black_nib: **Review** 23 | 24 | - 로직을 생각하기 크게 어렵지 않은 DP문제였다. 25 | -------------------------------------------------------------------------------- /BOJ/[1932] 정수 삼각형/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [1932] 정수 삼각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 아래층으로 합 누적 11 | for (int j = 1; j <= i; j++) { 12 | temp[j] = curLine[j] + Math.max(prevLine[j - 1], prevLine[j]); 13 | } 14 | prevLine = temp; 15 | ``` 16 | 17 | - 이전 행의 정보를 이용하여 큰 값을 아래로 누적시키며 마지막 줄의 숫자 중 가장 큰 수를 출력한다. 18 | 19 | ## :black_nib: **Review** 20 | 21 | - 한번 풀어봤던 DP문제여서 비교적 쉽게 풀 수 있었다. 22 | -------------------------------------------------------------------------------- /BOJ/[1932] 정수 삼각형/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [1932] 정수 삼각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 초기값 설정 11 | dp[n-1] = triangle[n-1].clone(); 12 | 13 | for(int i=n-2; i>=0; i--) { 14 | for(int j=0; j= N) { 27 | nx = 0; 28 | } 29 | if (ny < 0) { 30 | ny = M - 1; 31 | } 32 | if (ny >= M) { 33 | ny = 0; 34 | } 35 | 36 | findNumberOfCases(nx, ny, depth + 1, result + world[nx][ny]); 37 | } 38 | } 39 | ``` 40 | 41 | - 만들어야 할 단어 중 가장 길이가 긴 것을 변수에 저장한다. 42 | - Depth가 변수만큼 되었다면 만들어야 할 단어가 만들어 졌는지 확인한다. 43 | 44 | ## :black_nib: **Review** 45 | 46 | - BFS로 쉽게 풀 수 있는 문제였다! 47 | -------------------------------------------------------------------------------- /BOJ/[20168] 골목 대장 호석 - 기능성/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [20168] 골목 대장 호석 - 기능성 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void goAToB(int start, int max, int sum) { 11 | if(sum > C) { 12 | return; 13 | } 14 | 15 | if(start == B) { // 도착지에 도착하면 min값 갱신 16 | min = Math.min(max, min); 17 | check = true; 18 | return; 19 | } 20 | 21 | for(int i = 0; i < map[start].size(); i++) { 22 | int next = map[start].get(i).v; 23 | int cost = map[start].get(i).cost; 24 | 25 | if(visited[next]) { 26 | continue; 27 | } 28 | 29 | visited[next] = true; 30 | goAToB(next, Math.max(max, cost), sum+cost); 31 | visited[next] = false; 32 | } 33 | } 34 | ``` 35 | 36 | - 출발지에서 갈 수 있는 모든 방향을 DFS로 탐색한다. 37 | - 다음 교차로로 넘어갈 때마다 요금의 max값을 갱신하고, 수치심을 최소화 해야 하기 때문에 도착하면 max값 중 min값을 갱신한다. 38 | 39 | ## :black_nib: **Review** 40 | 41 | - 양방향 그래프 복습할 수 있었던 문제였다! 42 | -------------------------------------------------------------------------------- /BOJ/[20168] 골목 대장 호석 - 기능성/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [20168] 골목 대장 호석 - 기능성 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 백 트래킹 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void findMinCost() { 11 | visited[A] = true; 12 | goRoad(A, 0, 0); 13 | } 14 | 15 | private static void goRoad(int start, int max, int sum) { 16 | if(sum > C) { 17 | return; 18 | } 19 | if(start == B) { 20 | answer = Math.min(max, answer); 21 | return; 22 | } 23 | for (int[] destination : roads[start]) { 24 | if (!visited[destination[0]]) { 25 | visited[destination[0]] = true; 26 | goRoad(destination[0], Math.max(max, destination[1]), sum + destination[1]); 27 | visited[destination[0]] = false; 28 | } 29 | } 30 | } 31 | ``` 32 | 33 | - 상납할 요금이 부족하면 return한다. 34 | - 목적지에 도착하면 가장 수치심이 적게 든 길로 왔는지 check 후 answer를 갱신해준다. 35 | 36 | ## :black_nib: **Review** 37 | 38 | - 단순한 백트래킹 문제라 생각했으나.. 39 | - 부분 채점 문제였는데 12/18개 밖에 맞추지 못하였다. 40 | - sum + destination[1] 을 sum += dsetination[1]으로 했다 ㅎㅎ 사소한 실수 ^^ 41 | -------------------------------------------------------------------------------- /BOJ/[20168] 골목 대장 호석 - 기능성/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [20168] 골목 대장 호석 - 기능성 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 백트래킹 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | function dfs(p, totalCost, maxCost) { 11 | // 가진 돈보다 많이 사용한 경우 종료 12 | if (totalCost > C) { 13 | return; 14 | } 15 | if (minCost <= maxCost) { 16 | return; 17 | } 18 | // 도착지에 도착한 경우 종료 19 | if (p === B) { 20 | minCost = maxCost; 21 | return; 22 | } 23 | 24 | for (let next of alley[p]) { 25 | const [from, cost] = next; 26 | // 방문한 경우 무시 27 | if (visited[from]) { 28 | continue; 29 | } 30 | visited[from] = true; 31 | dfs(from, totalCost + cost, Math.max(maxCost, cost)); 32 | visited[from] = false; 33 | } 34 | } 35 | ``` 36 | 37 | - 백트레킹을 이용하여 종료 조건을 설정해뒀다. 38 | 39 | 1. 현재 가진 돈보다 요금을 많이 사용한 경우 종료한다. 40 | 2. 현재까지 나온 `minCost`의 값보다 `maxCost`가 크거나 같은 경우 더 볼 필요가 없으므로 종료한다. 41 | 3. 목적지에 도착한 경우 종료하고 `minCost`를 갱신해준다. 42 | 43 | ## :black_nib: **Review** 44 | 45 | - 기본적인 백트레킹 문제였다. 46 | - 어떻게 종료조건을 설정하는지가 중요한 문제였다. 47 | -------------------------------------------------------------------------------- /BOJ/[2056] 작업/jungu12/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.StringTokenizer; 5 | 6 | public class Main { 7 | public static void main(String[] args) throws IOException { 8 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | StringTokenizer st; 10 | 11 | int N = Integer.parseInt(br.readLine()); 12 | // 각각의 작업을 수행하는 데 걸리는 시간 13 | int[] dp = new int[N + 1]; 14 | 15 | int ans = 0; 16 | for (int i = 1; i <= N; i++) { 17 | st = new StringTokenizer(br.readLine()); 18 | int time = Integer.parseInt(st.nextToken()); 19 | int num = Integer.parseInt(st.nextToken()); 20 | 21 | dp[i] = time; 22 | for (int j = 0; j < num; j++) { 23 | int temp = Integer.parseInt(st.nextToken()); 24 | dp[i] = Math.max(dp[i], dp[temp] + time); 25 | } 26 | ans = Math.max(ans, dp[i]); 27 | } 28 | System.out.println(ans); 29 | } 30 | } -------------------------------------------------------------------------------- /BOJ/[2056] 작업/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [2056] 작업 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int N = Integer.parseInt(br.readLine()); 11 | // 각각의 작업을 수행하는 데 걸리는 시간 12 | int[] dp = new int[N + 1]; 13 | 14 | int ans = 0; 15 | for (int i = 1; i <= N; i++) { 16 | st = new StringTokenizer(br.readLine()); 17 | int time = Integer.parseInt(st.nextToken()); 18 | int num = Integer.parseInt(st.nextToken()); 19 | 20 | dp[i] = time; 21 | for (int j = 0; j < num; j++) { 22 | int temp = Integer.parseInt(st.nextToken()); 23 | dp[i] = Math.max(dp[i], dp[temp] + time); 24 | } 25 | ans = Math.max(ans, dp[i]); 26 | } 27 | System.out.println(ans); 28 | ``` 29 | 30 | - k번째 작업의 선행 작업들은 모두 k미만 번째 작업이다. 31 | - 그래서 따로 정렬이 필요 없이 dp를 활용하여 풀 수 있다. 32 | 33 | ## :black_nib: **Review** 34 | 35 | - 위상 정렬로 풀고 싶었는데 잘 이해가 되지 않는다.. 36 | -------------------------------------------------------------------------------- /BOJ/[2056] 작업/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [2056] 작업 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 위상 정렬 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | while (queue.length) { 11 | let x = queue.shift(); 12 | for (let next of graph[x]) { 13 | indegrees[next]--; 14 | finish_time[next] = Math.max( 15 | finish_time[next], 16 | finish_time[x] + time[next] 17 | ); 18 | if (indegrees[next] === 0) queue.push(next); 19 | } 20 | } 21 | ``` 22 | 23 | - 선행 작업이 끝났다면 해당 작업의 indegrees를 1낮춘다. 24 | - indegrees가 0이 된 작업은 실행할 수 있는 작업이므로 `queue`에 넣어준다. 25 | 26 | ## :black_nib: **Review** 27 | 28 | - 위상정렬 문제를 처음 접해봐서 어떻게 풀어야할지 감이 잡히지 않아 위상정렬부터 공부했다... 29 | - 비슷한 유형의 문제를 더 풀어서 완벽히 이해할 수 있도록 해야갰다. 30 | -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [2156] 포도주 시식 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int cur = 1; cur < n; cur++) { 11 | // 현재 와인을 마시지 않을때 12 | maxWine[cur] = maxWine[cur-1]; 13 | 14 | // 연속으로 먹지 않을때 15 | int pre = (cur - 2 < 0)?0 : maxWine[cur-2]; 16 | maxWine[cur] = Math.max(maxWine[cur], wine[cur] + pre); 17 | 18 | // 두잔을 연속으로 먹을때 19 | pre = (cur - 3 < 0)?0 : maxWine[cur-3]; 20 | maxWine[cur] = Math.max(maxWine[cur], wine[cur]+wine[cur-1]+pre); 21 | } 22 | ``` 23 | 24 | 3가지 경우를 나눠 dp를 사용하는 문제이다 25 | 1. 현재 번호의 포도주를 마시시 않았을 때 : **maxWine[cur-1]** 26 | 2. 현재 포도주를 마시고 이전 번호의 포도주를 마시지 않았을 때 : **maxWine[cur-2] + wine[cur]** 27 | 3. 현재 포도주를 마시고 이전 번호의 포도주 마셨을 때 : **maxWine[cur-3] + wine[cur-1] + wine[cur]** 28 |

29 | 위 3가지 경우 중 가장 큰 값을 maxWine[i]에 저장하면 maxWine[i]는 i번째에서 가장 많이 마시는 와인의 양이 된다. 30 | 31 | ## :black_nib: **Review** 32 | 33 | - i번째 포도주를 마시시 않는 상황도 생각을 했어야 했다. 무조건 i번째를 마신 경우에 대해서만 최대값을 구하는 생각에 사로잡혀서 푸는데 시간이 걸렸다. -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/SUbbb/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | public class Main { 4 | public static void main(String[] args) throws IOException { 5 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 6 | int N = Integer.parseInt(br.readLine()); 7 | int[] wines = new int[N]; 8 | 9 | for (int index = 0; index < N; index++) { 10 | wines[index] = Integer.parseInt(br.readLine()); 11 | } 12 | 13 | int[][] dp = new int[N][3]; 14 | dp[0][0] = dp[0][1] = wines[0]; 15 | 16 | for (int index = 1; index < N; index++) { 17 | dp[index][0] = wines[index] + dp[index - 1][1]; 18 | dp[index][1] = wines[index] + dp[index - 1][2]; 19 | dp[index][2] = Math.max(dp[index - 1][0], Math.max(dp[index - 1][1], dp[index - 1][2])); 20 | } 21 | 22 | System.out.println(Math.max(dp[N - 1][0], Math.max(dp[N - 1][1], dp[N - 1][2]))); 23 | } 24 | } -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [2156] 포도주 시식 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int index = 1; index < N; index++) { 11 | dp[index][0] = wines[index] + dp[index - 1][1]; 12 | dp[index][1] = wines[index] + dp[index - 1][2]; 13 | dp[index][2] = Math.max(dp[index - 1][0], Math.max(dp[index - 1][1], dp[index - 1][2])); 14 | } 15 | ``` 16 | 17 | - 2차원 배열을 사용했다. 18 | - [i][0] : i - 1번째 포도주를 시식하고, 현재 포도주도 시식하는 경우 19 | - [i][1] : i - 1번째 포도주를 시식하지 않고, 현재 포도주를 시식하는 경우 20 | - [i][2] : 현재 포도주를 시식하지 않는 경우 21 | 22 | ## :black_nib: **Review** 23 | 24 | - 처음에는 "현재 포도주를 시식하거나, 시식하지 않거나"와 같이 2가지 경우로 나눠 생각했다. 25 | - 이후에 "이전 포도주를 시식하거나, 시식하지 않는 경우"로 변경했다가, 현재 포도주를 무조건 먹지 않는 경우가 있을 수도 있음을 간과하는 바람에 추가해줬다! 26 | -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/asever0318/Main_2156.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | public class Main { 4 | static int N, max; 5 | static int[] wine, wineSum; 6 | 7 | public static void main(String[] args) throws IOException { 8 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 9 | N = Integer.parseInt(br.readLine()); 10 | wine = new int[N+3]; 11 | wineSum = new int[N+3]; // 첫 잔부터 탐색하기 위해서 앞에 3칸 비우기 12 | 13 | for(int i = 3; i < N+3; i++) { 14 | wine[i] = Integer.parseInt(br.readLine()); 15 | } 16 | 17 | System.out.println(getMax()); 18 | } 19 | 20 | static int getMax() { 21 | 22 | for(int i = 3; i < N+3; i++) { 23 | // i번째 잔을 마시는 경우 24 | int sum1 = wine[i] + wineSum[i-2]; // 전전잔을 마시는 경우 25 | int sum2 = wineSum[i-3] + wine[i-1] + wine[i]; // 이전잔을 마시는 경우 26 | int max = Math.max(sum1, sum2); 27 | 28 | // i번째 잔을 안마시는 경우와 비교하여 더 큰 값 저장 29 | wineSum[i] = Math.max(max, wineSum[i-1]); 30 | } 31 | 32 | return wineSum[N+2]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [2156] 포도주 시식 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static int getMax() { 11 | 12 | for(int i = 3; i < N+3; i++) { 13 | // i번째 잔을 마시는 경우 14 | int sum1 = wine[i] + wineSum[i-2]; 15 | int sum2 = wineSum[i-3] + wine[i-1] + wine[i]; 16 | int max = Math.max(sum1, sum2); 17 | 18 | // i번째 잔을 안마시는 경우와 비교하여 더 큰 값 저장 19 | wineSum[i] = Math.max(max, wineSum[i-1]); 20 | } 21 | 22 | return wineSum[N+2]; 23 | } 24 | ``` 25 | - N+3크기로 각 순서의 포도주를 고려할 때의 최대값을 담는 DP배열을 만든다. 26 | - i번째 포도주를 고려하는 경우는 2가지로 1. i번째 잔을 마실 때, 2. i번째 잔을 마시지 않을 때 2가지로 나눌 수 있다. 27 | - 연속 3개의 잔을 마실 수 없기 때문에 i번째 잔을 마시는 경우는 2가지로 나뉜다. 28 | 1. 바로 이전 잔[i-1]을 마시는 경우와 2. 전전 잔[i-2]을 마시는 경우로 sum1과 sum2로 나누어 구해준 후 둘 중 더 큰 값을 max값으로 정한다. 29 | - 마지막으로 i번째 잔을 마시지 않는 경우와 max값 중 더 큰 값을 dp배열에 저장한다. 30 | - 마지막 인덱스에 저장된 값이 구하고자 하는 최대값이 된다. 31 | 32 | 33 | ## :black_nib: **Review** 34 | - DP는 항상 점화식 찾는 게 어렵다 -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/jungu12/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.io.IOException; 4 | 5 | public class Main { 6 | public static void main(String[] args) throws IOException { 7 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 8 | 9 | int N = Integer.parseInt(br.readLine()); 10 | int[] table = new int[N + 1]; 11 | int[] dp = new int[N + 1]; 12 | 13 | for (int i = 1; i <= N; i++) { 14 | table[i] = Integer.parseInt(br.readLine()); 15 | } 16 | 17 | dp[1] = table[1]; 18 | 19 | if (N > 1) { 20 | dp[2] = table[1] + table[2]; 21 | } 22 | 23 | for (int i = 3; i <= N; i++) { 24 | dp[i] = Math.max(dp[i - 1], Math.max(dp[i - 2] + table[i], dp[i - 3] + table[i - 1] + table[i])); 25 | } 26 | 27 | System.out.println(dp[N]); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/ksg2388/Main.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const filePath = process.platform === 'linux' ? '/dev/stdin' : 'input.txt'; 3 | let [n, ...arr] = fs 4 | .readFileSync(filePath) 5 | .toString() 6 | .trim() 7 | .split('\n') 8 | .map(Number); 9 | 10 | console.log(findMaxGrape(n)); 11 | 12 | function findMaxGrape(n) { 13 | let dp = Array(n).fill(0); 14 | 15 | if (n === 1) { 16 | return arr[0]; 17 | } 18 | 19 | if (n === 2) { 20 | return arr[0] + arr[1]; 21 | } 22 | 23 | dp[0] = arr[0]; 24 | dp[1] = dp[0] + arr[1]; 25 | dp[2] = Math.max(dp[1], arr[1] + arr[2], arr[0] + arr[2]); 26 | 27 | for (let i = 3; i < n; i++) { 28 | dp[i] = Math.max( 29 | dp[i - 1], // 1, 2번째 마시기 30 | dp[i - 2] + arr[i], // 1, 3번째 마시기 31 | dp[i - 3] + arr[i - 1] + arr[i] // 2, 3번째 마시기 32 | ); 33 | } 34 | 35 | return dp[n - 1]; 36 | } 37 | -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [2156] 포도주 시식 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | dp[0] = arr[0]; 11 | dp[1] = dp[0] + arr[1]; 12 | dp[2] = Math.max(dp[1], arr[1] + arr[2], arr[0] + arr[2]); 13 | 14 | for (let i = 3; i < n; i++) { 15 | dp[i] = Math.max( 16 | dp[i - 1], // 1, 2번째 마시기 17 | dp[i - 2] + arr[i], // 1, 3번째 마시기 18 | dp[i - 3] + arr[i - 1] + arr[i] // 2, 3번째 마시기 19 | ); 20 | } 21 | ``` 22 | 23 | - 포도주를 3잔 연속으로 마실 수 없기 때문에 세울 수 있는 점화식은 24 | dp[i] = Math.max( 25 | dp[i - 1], 26 | dp[i - 2] + arr[i], 27 | dp[i - 3] + arr[i - 1] + arr[i] 28 | ); 29 | 이 된다. 30 | 31 | ## :black_nib: **Review** 32 | 33 | - 문제를 읽자마자 DP로 풀어야겠다는 생각은 들었는데 점화식을 떠올리는데 시간이 조금 걸렸다. 34 | - DP문제들은 다 조금씩 비슷하면서 조금씩 달라서 어렵다... 35 | -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/yeahLim/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.InputStreamReader; 3 | import java.util.StringTokenizer; 4 | 5 | public class Main { 6 | 7 | public static void main(String[] args) throws Exception { 8 | 9 | /* 입력 */ 10 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 11 | int n = Integer.parseInt(br.readLine()); 12 | int[] wine = new int[n+1]; 13 | 14 | for (int i = 1; i < n+1; i++) { 15 | wine[i] = Integer.parseInt(br.readLine()); 16 | } 17 | 18 | int[] dp = new int[n+1]; 19 | 20 | // 초기값 설정 21 | dp[1] = wine[1]; 22 | 23 | // n = 1일 경우 예외처리 24 | if (n > 1) { 25 | dp[2] = wine[1] + wine[2]; 26 | } 27 | 28 | for (int i = 3; i <= n; i++) { 29 | dp[i] = Math.max(dp[i-1], Math.max(dp[i-2], dp[i-3] + wine[i-1]) + wine[i]); 30 | } 31 | System.out.println(dp[n]); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /BOJ/[2156] 포도주 시식/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [2156] 포도주 시식 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 초기값 설정 11 | dp[1] = wine[1]; 12 | 13 | // n = 1일 경우 예외처리 14 | if (n > 1) { 15 | dp[2] = wine[1] + wine[2]; 16 | } 17 | 18 | for (int i = 3; i <= n; i++) { 19 | dp[i] = Math.max(dp[i-1], Math.max(dp[i-2], dp[i-3] + wine[i-1]) + wine[i]); 20 | } 21 | ``` 22 | 23 | - 24 | 25 | ## :black_nib: **Review** 26 | 27 | - 요즘 dp문제가 어렵드아 28 | -------------------------------------------------------------------------------- /BOJ/[2206] 벽 부수고 이동하기/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [2206] 벽 부수고 이동하기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 벽이고, 이전에 벽을 부순 적이 없는 경우 11 | if (map[nx][ny] == 1 && !isBoomed) { 12 | isVisited[nx][ny][1] = true; 13 | path.add(new Location(nx, ny, nCost, true)); 14 | } 15 | // 벽이 아닌 경우 16 | else if (map[nx][ny] == 0){ 17 | // 이전에 벽을 부순 적이 있고, 방문한 적이 없다면 18 | if (isBoomed && !isVisited[nx][ny][1]) { 19 | isVisited[nx][ny][1] = true; 20 | path.add(new Location(nx, ny, nCost, isBoomed)); 21 | } 22 | // 이전에 벽을 부순 적이 없고, 방문한 적이 없다면 23 | else if (!isBoomed && !isVisited[nx][ny][0]){ 24 | isVisited[nx][ny][0] = true; 25 | path.add(new Location(nx, ny, nCost, isBoomed)); 26 | } 27 | } 28 | ``` 29 | 30 | - 벽을 부수거나, 부수지 않은 경우에 대해 모두 최단 경로를 구한다. 31 | 32 | ## :black_nib: **Review** 33 | - 아이디어는 금방 떠올릴 수 있었는데, 3차원 배열을 만드는 구현에서 좀 막혀서 정답 코드를 참고했다... -------------------------------------------------------------------------------- /BOJ/[2206] 벽 부수고 이동하기/asever0318/Main_2206.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SeongukBaek/algoStudy/5a78a90aaa35a61887d5e02a2355c656a48c98be/BOJ/[2206] 벽 부수고 이동하기/asever0318/Main_2206.java -------------------------------------------------------------------------------- /BOJ/[2206] 벽 부수고 이동하기/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [2206] 벽 부수고 이동하기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | if (map[nx][ny] == 0) { 11 | if (!visited[cur[3]][nx][ny]) { 12 | q.add(new int[] { nx, ny, cur[2] + 1, cur[3] }); 13 | visited[cur[3]][nx][ny] = true; 14 | } 15 | }else { 16 | if (cur[3] == 0 && !visited[1][nx][ny]) { 17 | q.add(new int[] { nx, ny, cur[2] + 1, 1 }); 18 | visited[1][nx][ny] = true; 19 | } 20 | } 21 | ``` 22 | - q에 배열을 넣어주는데, 그 배열에 {(x좌표, y좌표, 칸을 지난 횟수, 벽을 부순 유무)}를 저장한다. 23 | - visited 배열을 벽을 부수었을 때, 안 부수었을 때 따로 관리해야 함으로, 3차원 배열로 만들어 주었다. 24 | - 벽이 아닐 때는 (칸을 지난 횟수 + 1) 해준 후 큐에 삽입한다. 25 | - 벽일 때는 (칸을 지난 횟수 + 1), 벽을 부순 유무를 1로 바꿔준 후 큐에 삽입한다. 26 | 27 | 28 | ## :black_nib: **Review** 29 | - visited 배열을 벽을 부수었을 때, 안 부수었을 때 따로 관리해야 한다는 생각을 하기 힘들었다. 30 | - queue에 삽입하는 배열에 너무 많은 값이 들어가기에, class로 관리해 주는게 조금 더 좋은 방식 같다. 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /BOJ/[2206] 벽 부수고 이동하기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [2206] 벽 부수고 이동하기 2 | 3 | ## :pushpin: **Algorithm** 4 | BFS 5 | 6 | ## :round_pushpin: **Logic** 7 | ``` java 8 | Place(int x, int y, int dis, int breakCnt) { 9 | this.x = x; 10 | this.y = y; 11 | this.dis = dis; 12 | this.breakCnt = breakCnt; 13 | } 14 | ``` 15 | - visited배열을 int타입으로 설정해 초기 값을 엄청 큰 값으로 설정해준다. 16 | - 벽을 부순 경우 breakCnt에 값을 증가시켜주고 이동 시 visited보다 breakCnt값이 작은 경우에는 그 위치로 방문할 수가 있다. 17 | 18 | ## :black_nib: **Review** 19 | - 처음에 문제를 접근할 때 DFS를 이용해 접근했는데 시간초과가 났다. 최단경로 문제를 해결할때는 BFS를 사용해야 한다는 것을 알았다. -------------------------------------------------------------------------------- /BOJ/[2263] 트리의 순회/HyeW/Main.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SeongukBaek/algoStudy/5a78a90aaa35a61887d5e02a2355c656a48c98be/BOJ/[2263] 트리의 순회/HyeW/Main.java -------------------------------------------------------------------------------- /BOJ/[2263] 트리의 순회/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [2263] 트리의 순회 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 트리, 분할정복, 재귀 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void getPreorder(int inStart, int inEnd, int pStart, int pEnd) { 11 | if(inStart > inEnd || pStart > pEnd) { 12 | return; 13 | } 14 | 15 | int inRootIndex = inorderParent[postorder[pEnd]]; 16 | int leftChild = inRootIndex - inStart; 17 | 18 | preorder[preIndex++] = postorder[pEnd]; 19 | // 왼쪽 서브 트리 20 | getPreorder(inStart, inRootIndex -1, pStart, leftChild+pStart-1); 21 | // 오른쪽 서브 트리 22 | getPreorder(inRootIndex + 1,inEnd, leftChild+pStart, pEnd - 1); 23 | 24 | } 25 | ``` 26 | 27 | - postorder로 루트를 찾고 inorder로 트리의 사이즈를 구한다. 28 | 29 | ## :black_nib: **Review** 30 | 31 | - 로직은 조금만 생각하면 분할 정복으로 할 수 있다는 것을 알 수 있었다. 32 | - 풀이 방법도 떠올랐는데 문제가 분할 정복을 하면서 전달해야 하는 인자 값을 정하기가 어렵다는 것이다. 계속 고민을 하다가 머리가 복잡해져서 그 부분은 다른 사람의 풀이를 참고하여 해결했다.. 33 | - 하지만 아직도 그렇게 4개의 인자를 줘야하는 이유를 모르겠다.. 트리의 사이즈와 inorder와 postorder의 시작점만 넘겨주면 안되는건가..? 더 공부해 봐야겠다. -------------------------------------------------------------------------------- /BOJ/[2263] 트리의 순회/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [2263] 트리의 순회 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | Divide and Conquer 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void getPreOrder(int inStart, int inEnd, int postStart, int postEnd) { 11 | if (inStart > inEnd) { 12 | return; 13 | } 14 | 15 | int root = postOrder[postEnd]; 16 | sb.append(root + " "); 17 | 18 | int rootIdx = inOrderIdx[root]; 19 | 20 | int left = rootIdx - inStart; 21 | 22 | getPreOrder(inStart, rootIdx - 1, postStart, postStart + left - 1); 23 | 24 | getPreOrder(rootIdx + 1, inEnd, postStart + left, postEnd - 1); 25 | } 26 | ``` 27 | 28 | - postorder의 마지막 idx는 root이다. 29 | - inorder root의 idx를 기준으로 좌측은 좌측 자식 노드, 우측은 우측 자식 노드이다. 30 | - 위 로직을 토대로 Node가 하나 남을 때 까지 돌아준다. 31 | 32 | ## :black_nib: **Review** 33 | 34 | - 어렵다... 35 | -------------------------------------------------------------------------------- /BOJ/[2263] 트리의 순회/ksg2388/Main.js: -------------------------------------------------------------------------------- 1 | const [n, io, po] = require('fs') 2 | .readFileSync('/dev/stdin') 3 | .toString() 4 | .trim() 5 | .split('\n'); 6 | const indexArr = Array(n); 7 | const inOrder = io.split(' ').forEach((e, i) => (indexArr[e] = i)); 8 | const postOrder = po.split(' '); 9 | let ans = ''; 10 | 11 | const DFS = (inStart, inEnd, postStart, postEnd) => { 12 | if (inStart > inEnd || postStart > postEnd) return; 13 | const root = postOrder[postEnd]; 14 | ans += root + ' '; 15 | let idx = indexArr[root]; 16 | const leftCnt = idx - inStart; 17 | DFS(inStart, idx - 1, postStart, postStart + leftCnt - 1); 18 | DFS(idx + 1, inEnd, postStart + leftCnt, postEnd - 1); 19 | }; 20 | 21 | DFS(0, n - 1, 0, n - 1); 22 | console.log(ans); 23 | -------------------------------------------------------------------------------- /BOJ/[2263] 트리의 순회/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [2263] 트리의 순회 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 트리, 분할정복 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | const DFS = (inStart, inEnd, postStart, postEnd) => { 11 | if (inStart > inEnd || postStart > postEnd) return; 12 | const root = postOrder[postEnd]; 13 | ans += root + ' '; 14 | let idx = indexArr[root]; 15 | const leftCnt = idx - inStart; 16 | DFS(inStart, idx - 1, postStart, postStart + leftCnt - 1); 17 | DFS(idx + 1, inEnd, postStart + leftCnt, postEnd - 1); 18 | }; 19 | ``` 20 | 21 | - postOrder의 맨 마지막 숫자가 Root -> 그 Root 값을 inOrder에서 찾아 index 값을 기억 -> 그 index를 기준으로 postOrder를 다시 index의 앞, 뒤로 서브트리 분리. 22 | 23 | - 위 과정을 반복하면서 preOrder를 구한다. 24 | 25 | ## :black_nib: **Review** 26 | 27 | - 트리에 대한 지식 부족으로 풀이를 참고했다. 28 | - 분할정복에 대해서도 익숙하지 않아서 풀이를 봤는데도 어려웠다... 29 | -------------------------------------------------------------------------------- /BOJ/[2527] 직사각형/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [2527] 직사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학, 기하학, 많은 조건 분기 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void checkSquare() { 11 | 12 | // 안겹칠 때 13 | if (p1 < x2 || q1 < y2 || p2 < x1 || q2 < y1) { 14 | System.out.println("d"); 15 | } // 점일 때 16 | else if ((x1 == p2 && y1 == q2) || (x1 == p2 && q1 == y2) || (p1 == x2 && q1 == y2) || (p1 == x2 && y1 == q2)) { 17 | System.out.println("c"); 18 | } // 선분일 때 19 | else if (p1 == x2 || q1 == y2|| p2 == x1 || y1 == q2){ 20 | System.out.println("b"); 21 | } // 직사각형으로 겹칠 때 22 | else { 23 | System.out.println("a"); 24 | } 25 | } 26 | ``` 27 | 28 | - 두 개의 사각형이 안겹칠 때, 점일 때, 선분일 때, 직사각형으로 겹칠 때 총 4가지 경우로 나누어서 좌표 비교를 통해 문제를 풀었다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 좌표 비교하는 게 생각보다 어려워서 오래걸렸다.. 다음엔 다른 방법으로 풀어야지.. 33 | -------------------------------------------------------------------------------- /BOJ/[2527] 직사각형/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [2527] 직사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void findOverlapedShape(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { 11 | if (x2 < x3 || y2 < y3 || x4 < x1 || y4 < y1) { 12 | System.out.println("d"); 13 | return; 14 | } 15 | if ((x2 == x3 && y2 == y3) || (x2 == x3 && y1 == y4) || (x1 == x4 && y2 == y3) || (x1 == x4 && y1 == y4)) { 16 | System.out.println("c"); 17 | return; 18 | } 19 | if (x2 == x3 || y2 == y3 || x1 == x4 || y1 == y4) { 20 | System.out.println("b"); 21 | return; 22 | } 23 | System.out.println("a"); 24 | 25 | } 26 | ``` 27 | 28 | - 좌표로 비교하는 방식으로 구현하였다. 29 | - 선분일 때, x좌표가 같으면 y좌표가 달라야하고, y좌표가 같다면 x좌표는 달라야하는 조건을 달아야하나, 30 | 점일 때를 조기 반환 해주었음으로 조건을 생략할 수 있다. 31 | 32 | ## :black_nib: **Review** 33 | 34 | - 좌표로 푸니까 실수하면 찾기 너무 힘들었다.. 35 | - 그래도 다음에도 좌표로 풀 것 같다. 36 | -------------------------------------------------------------------------------- /BOJ/[2527] 직사각형/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [2527] 직사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 공통 부분 : 없음 11 | if(p2 < x1 || x2 > p1 || q2 < y1 || y2 > q1) { 12 | System.out.println("d"); 13 | } 14 | 15 | // 공통 부분 : 점 16 | else if((x1 == p2 && y1 == q2) || (x2 == p1 && y2 == q1) || (x2 == p1 && y1 == q2) || (x1 == p2 && y2 == q1)) { 17 | System.out.println("c"); 18 | } 19 | 20 | // 공통 부분 : 선분 21 | else if(x1 == p2 || x2 == p1 || y1 == q2 || y2 == q1) { 22 | System.out.println("b"); 23 | } 24 | 25 | // 공통 부분 : 직사각형 26 | else System.out.println("a"); 27 | ``` 28 | 29 | - 겹치는 부분이 없다면, d 30 | - 모서리 중에 하나가 겹치면 c 31 | - 선분이 겹치면 b 32 | - 이외의 경우는 a 33 | 34 | ## :black_nib: **Review** 35 | 36 | - 단순 구현문제였지만, 좌표 문제를 볼때는 꼼꼼하게 봐야겠다. 좌표하나를 잘못 적어서 시간이 좀 걸렸다. 37 | -------------------------------------------------------------------------------- /BOJ/[2529] 부등호/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | DFS(백트레킹)를 사용 3 | 4 | ## 중요 구현 로직 및 설명 5 | 부등호를 따로 저장해둔뒤에 dfs 함수를 통해 부등호에 만족하는 모든 경우의 수를 구한다. 이후 result 배열을 정렬해 맨 앞의 값(최소값)과 맨 뒷 값(최대값)을 출력한다. 6 | 7 | 여기서 종료 조건은 depth가 k + 1일 때, 즉 부등호의 개수보다 하나 많을 때 그 값을 result에 추가한다. 8 | 재귀 호출 부분은 일단 num에 아무 값도 없는 경우는 무조건 호출을 하고 그 이외의 경우는 compare 함수를 통해 이전의 값과 부등호를 비교하여 옳은 경우에만 재귀 호출한다. 9 | 10 | ## 풀이 후기 11 | 아직은 자바에 익숙하지 않아서 적절한 기능들을 사용한 것인지 잘 모르겠다. 더 효율적으로 코드를 짤 수 있도록 신경써야겠다. 12 | -------------------------------------------------------------------------------- /BOJ/[2529] 부등호/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [2529] 부등호 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 브루트포스, 백트래킹 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static List result = new ArrayList<>(); 11 | ``` 12 | 13 | - 결과값 담을 arrayList 객체 14 | 15 | ```java 16 | private static void dfs(String n, int depth) { 17 | if (depth == k + 1) { 18 | result.add(n); 19 | return; 20 | } 21 | for (int i = 0; i <= 9; i++) { 22 | if (depth == 0 || !visited[i] && check(n.charAt(n.length() - 1) - '0', i, signs[depth - 1])) { 23 | visited[i] = true; 24 | dfs(n + i, depth + 1); 25 | visited[i] = false; 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | - 첫번째 숫자와 두번째 숫자와 부등호를 check함수에 넘겨 조건에 부합하고, 0~9까지의 모든 숫자가 다 부합하면 result에 문자열 넣어주고 종료 32 | - 부등호의 개수가 하나 더 많아지면 종료 33 | 34 | ## :black_nib: **Review** 35 | - List 타입에 ArrayList 객체 생성 36 | - List가 ArrayList의 부모 객체이기 때문에 더 자유롭게 사용 가능 37 | -------------------------------------------------------------------------------- /BOJ/[26215] 눈 치우기/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [26215] 눈 치우기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 그리디, 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static List cleanTwoHouses() { 11 | List temp = new ArrayList<>(); 12 | for (int index = 0; index < MAX_HOUSE_COUNT; index++) { 13 | if (snows.isEmpty()) { 14 | break; 15 | } 16 | int snow = snows.poll() - 1; 17 | if (snow == 0) { 18 | continue; 19 | } 20 | temp.add(snow); 21 | } 22 | return temp; 23 | } 24 | ``` 25 | 26 | - 내림차순으로 정렬된 우선순위 큐에서 두 개의 집 앞에 쌓인 눈을 하나씩 제거한다. 27 | - 눈이 0이 되면 큐에 넣지 않는다. 28 | 29 | ## :black_nib: **Review** 30 | - 눈을 내림차순으로 계속 정렬하면서, 2 집씩 감소시키는 것이 중요한 문제였고, 이를 위해 우선순위 큐를 사용해야겠다고 생각했다. -------------------------------------------------------------------------------- /BOJ/[26215] 눈 치우기/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [26215] 눈 치우기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void clean() { 11 | if(snows.peek() > 1440) { 12 | time = -1; 13 | return; 14 | } 15 | while(!snows.isEmpty()) { 16 | time++; 17 | cleanSnow(); 18 | } 19 | } 20 | 21 | static void cleanSnow() { 22 | List tmp = new ArrayList<>(); 23 | for(int i = 0; i < 2; i++) { 24 | if(snows.isEmpty()) 25 | break; 26 | int snow = snows.poll() -1; 27 | if(snow == 0) 28 | continue; 29 | tmp.add(snow); 30 | } 31 | snows.addAll(tmp); 32 | } 33 | ``` 34 | - 우선순위 큐에 집 앞 쌓인 눈의 양을 넣고 큐가 빌 때 까지 두 집의 눈의 양을 하나씩 줄여 나간다. 35 | - 시작 전, peek()한 값이 1440를 넘는지, 끝내기 전 결과값이 1440를 넘는지 확인해준다. 36 | 37 | 38 | ## :black_nib: **Review** 39 | - 큐가 빈 후 결과값이 1440를 넘는지 확인하는 로직의 필요성을 뒤늦게 알아차렸다. 40 | - 한 집 앞의 눈의 양이 전체 눈의 양이 반이 넘는 경우 결과 값은 해당 집의 눈의 양, 그렇지 않다면 sum /2 + 나머지 라는 방법도 생각하였으나 이 방법으론 풀지 못하였다. 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /BOJ/[26215] 눈 치우기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 우선순위큐 4 | 5 | ## 중요 구현 로직 및 설명 6 | 7 | 우선순위 큐를 사용해서 내림차순으로 정렬 후 눈치우기 작업을 반복 8 | 9 | 1. 배열을 내림차순으로 정렬 10 | 2. 가장 큰 값이 1440보다 클 경우 -1 출력 후 종료 11 | 3. 가장 큰 값과 그 다음 큰 값에 1씩 빼는 작업을 남은 집이 1개보다 큰 경우 반복 12 | 4. 작업을 모두 끝낸 후 남은 값 만큼 시간에 더해준다. 13 | image 14 | 우선순위큐에서 가장 큰 값 2개를 꺼내서 각각 1씩 줄인 후 다시 우선순위큐에 넣고 시간을 증가시킨다. 값이 0이되는 경우는 넣지 않는다. 15 | 16 | ## 풀이 후기 17 | 18 | 입력값이 1440이 넘는 경우를 제외하고도 시간이 1440이 넘는 경우가 있었는데 그 경우를 생각하지 않고 문제를 풀다가 시간이 오래 걸려서 아쉬웠다. 19 | -------------------------------------------------------------------------------- /BOJ/[26215] 눈 치우기/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [26215] 눈 치우기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | - 가장 큰수를 기준으로 priority queue를 이용 9 | - 가장 큰 수 2개의 값에 -1를 해주면서, count값 증가 10 | ```java 11 | PriorityQueue pq = new PriorityQueue<>(Collections.reverseOrder()); // 우선순위 : 큰 숫자 12 | for (int i = 0; i < n; i++) 13 | pq.offer(arr[i]); 14 | while (pq.peek() != 0) { 15 | int tmp1 = pq.poll() - 1; 16 | int tmp2 = pq.poll() - 1; 17 | pq.offer(tmp1); 18 | pq.offer(tmp2); 19 | count++; 20 | } 21 | ``` 22 | 23 | ## :black_nib: **Review** 24 | - priority queue의 offer/add, poll/remove, peek/element의 차이에 대해 알게됨 25 | -------------------------------------------------------------------------------- /BOJ/[3020] 개똥벌레/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [3020] 개똥벌레 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 누적합 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 누적합 11 | for (int index = H - 2; index >= 0 ; index--) { 12 | ceil[index] += ceil[index + 1]; 13 | floor[index] += floor[index + 1]; 14 | } 15 | 16 | stone = new int[H]; 17 | int min = N + 1; 18 | 19 | for (int index = 0; index < H; index++) { 20 | stone[index] = floor[index] + ceil[H - 1 - index]; 21 | min = Math.min(min, stone[index]); 22 | } 23 | ``` 24 | 25 | - 종유석과 석순 배열을 뒤에서부터 누적합을 수행한다. 26 | - 길이가 긴 장애물부터 누적합을 수행하므로, 누적합한 후의 배열의 값은 해당 길이의 장애물로부터 파괴해야 하는 장애물의 수를 의미하게 된다. 27 | - 이제 1번째 구간부터 파괴해야 하는 석순과 종유석의 수를 확인하면서 최소 장애물 수를 찾는다. 28 | 29 | ## :black_nib: **Review** 30 | 31 | - 입력범위를 보고, 무작정 구현했다가는 시간초과가 날 것임을 알 수 있었다. 32 | - 주어진 값들을 다 쌓아서 한 번에 처리할 수 있지 않을까 싶어서 누적합을 사용해야 하나 했는데, 구체적인 방법이 떠오르지 않아서 참고했다.. 33 | - 그리고 이 문제에서 스트림을 사용하면서 알게 된 점을 공유.. 34 | - https://madplay.github.io/post/effectively-final-in-java 35 | -------------------------------------------------------------------------------- /BOJ/[3020] 개똥벌레/ksg2388/Main.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const input = fs.readFileSync('/dev/stdin').toString().split('\n'); 3 | 4 | const [n, h] = input.shift().split(' ').map(Number); 5 | const top = Array(h + 1).fill(0); 6 | const bottom = Array(h + 1).fill(0); 7 | let minCount = 200001; 8 | let count = 0; 9 | 10 | input.forEach((element, index) => { 11 | if (index % 2 === 0) { 12 | bottom[element]++; 13 | return; 14 | } 15 | top[element]++; 16 | }); 17 | 18 | // 낮은 높이로 내려가면서 값 누적 19 | for (let i = h - 1; i > 0; i--) { 20 | bottom[i] += bottom[i + 1]; 21 | top[i] += top[i + 1]; 22 | } 23 | 24 | for (let i = 1; i <= h; i++) { 25 | if (minCount > bottom[i] + top[h - i + 1]) { 26 | minCount = bottom[i] + top[h - i + 1]; 27 | count = 1; 28 | continue; 29 | } 30 | if (minCount === bottom[i] + top[h - i + 1]) { 31 | count++; 32 | } 33 | } 34 | 35 | console.log(minCount + ' ' + count); 36 | -------------------------------------------------------------------------------- /BOJ/[3020] 개똥벌레/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [3020] 개똥벌레 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 누적합 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | input.forEach((element, index) => { 11 | if (index % 2 === 0) { 12 | bottom[element]++; 13 | return; 14 | } 15 | top[element]++; 16 | }); 17 | ``` 18 | 19 | - 종유석과 석순의 크기별 갯수를 각각 저장한다. 20 | 21 | ```javascript 22 | // 낮은 높이로 내려가면서 값 누적 23 | for (let i = h - 1; i > 0; i--) { 24 | bottom[i] += bottom[i + 1]; 25 | top[i] += top[i + 1]; 26 | } 27 | 28 | for (let i = 1; i <= h; i++) { 29 | if (minCount > bottom[i] + top[h - i + 1]) { 30 | minCount = bottom[i] + top[h - i + 1]; 31 | count = 1; 32 | continue; 33 | } 34 | if (minCount === bottom[i] + top[h - i + 1]) { 35 | count++; 36 | } 37 | } 38 | ``` 39 | 40 | - 낮은 높이로 내려가면서 그 값들을 누적시킨다. 41 | - 그리고 높이 1부터 h까지 각각 부딪히는 종유석과 석순의 개수를 확인하며 최소값과 최소값의 개수를 확인한다. 42 | 43 | ## :black_nib: **Review** 44 | 45 | - 문제를 보자마자 누적합을 사용해야겠다는 생각은 들었지만 어떤 방식으로 구현할지가 쉽지 않았다. 46 | - 결국 값을 미리 다 저장시켜두고 높이가 높은 곳에서 낮은곳으로 값을 누적시키는 방법을 선택했다. 47 | -------------------------------------------------------------------------------- /BOJ/[3020] 개똥벌레/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [3020] 개똥벌레 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 누적합 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 구간 개수 세기 11 | for (int i = 0; i < n / 2; i++) { 12 | floor[Integer.parseInt(br.readLine())]++; 13 | ceil[Integer.parseInt(br.readLine())]++; 14 | } 15 | 16 | // 누적합 17 | for (int i = h-1; i > 0; i--) { 18 | floor[i] += floor[i+1]; 19 | ceil[i] += ceil[i+1]; 20 | } 21 | ``` 22 | 23 | - 석순과 종유석 배열을 뒤에서부터 누적합을 구한다. 24 | - 높이가 높은 부분이 낮은 부분에도 반영이 되어야하기 때문에 25 | 26 | 27 | ```java 28 | for (int i = 1; i <= h; i++) { 29 | bar[i] = floor[i] + ceil[h-i+1]; // 전체 누적합 30 | if (min > bar[i]) { 31 | min = bar[i]; 32 | cnt = 1; 33 | } 34 | else if (min == bar[i]) { 35 | cnt++; 36 | } 37 | } 38 | ``` 39 | - 구간마다의 석순과 종유석의 전체 수를 구한다. 40 | - 그리고 가장 적은 장애물의 수와 그 구간들의 개수를 구한다. 41 | 42 | ## :black_nib: **Review** 43 | 44 | - 누적합도 일종의 dp라는 것을 알게되었다. 이렇게 응용된 누적합은 낯설다... 어려운 녀석이다.. 45 | -------------------------------------------------------------------------------- /BOJ/[3584] 가장 가까운 공통 조상/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [15565] 귀여운 라이언 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 투 포인터 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static int findMinSize() { 11 | int min = Integer.MAX_VALUE; 12 | int end = -1; 13 | int count = 0; 14 | for (int start = 0; start < N; start++) { 15 | while (end < N - 1 && count < K) { 16 | end++; 17 | if (dolls[end] == 1) { 18 | count++; 19 | } 20 | } 21 | 22 | if(count == K) { 23 | min = Math.min(min, end - start + 1); 24 | } 25 | 26 | if(dolls[start] == 1) { 27 | count--; 28 | } 29 | } 30 | 31 | if (min == Integer.MAX_VALUE) { 32 | return -1; 33 | } 34 | return min; 35 | } 36 | ``` 37 | 38 | - N이 최대 10의 6승이 될 수 있으니, O(n)의 시간으로 풀어줘야한다 -> 투 포인터! 39 | - 현재 투 포인터 내에 K개 만큼의 라이언이 없다면 계속 end++ 40 | - K개가 되었다면 start++하며 다음 라이언 위치까지 이동 41 | 42 | ## :black_nib: **Review** 43 | 44 | - 투 포인터의 개념만 서 있다면 풀 수 있는 문제였으나, 푸는데 시간이 다소 걸렸다.. 45 | -------------------------------------------------------------------------------- /BOJ/[4803] 트리/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [4803] 트리 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DPS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void makeEdge(int n) { 11 | visited[n] = true; 12 | vertexNum++; 13 | int connectedEdgeSize = graph[n].size(); 14 | edgeNum += connectedEdgeSize; 15 | for (int i = 0; i < connectedEdgeSize; i++) { 16 | int current = graph[n].get(i); 17 | if (visited[current]) { 18 | continue; 19 | } 20 | makeEdge(current); 21 | } 22 | } 23 | ``` 24 | 25 | - DFS를 이용하여 문제의 조건대로 트리를 만들어준다. 26 | 27 | ```java 28 | private static void countTree() { 29 | for (int i = 1; i <= N; i++) { 30 | if (!visited[i]) { 31 | vertexNum = 0; 32 | edgeNum = 0; 33 | makeEdge(i); 34 | if (edgeNum == (vertexNum - 1) * 2) { 35 | count++; 36 | } 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | - 트리는 간선의 수가 정점의 수 - 1이다. 43 | - 양방향 그래프로 만들어 주었음으로 위와 같이 계산해 주어 만족한다면 tree++ 44 | 45 | 46 | 47 | ## :black_nib: **Review** 48 | - 트리인지 확인하는 로직을 답을 봐버렸다.. 근데 안 잊어버릴듯. 49 | 50 | -------------------------------------------------------------------------------- /BOJ/[4803] 트리/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [4803] 트리 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void dfs(int idx) { 11 | for (int next : node.get(idx)) { 12 | // 방문했던 곳을 다시 방문시 사이클이 형성되므로 트리 X 13 | if (visited[next]) { 14 | isTree = false; 15 | return; 16 | } 17 | node.get(next).remove(idx); 18 | visited[next] = true; 19 | dfs(next); 20 | } 21 | return; 22 | } 23 | ``` 24 | 25 | - 방문했던 곳을 재방문 시 사이클이 형성되므로 트리가 아니게 된다. 26 | - 다음 위치를 방문하는 경우 그 이전 값과 연결되있던 정보를 다음 위치의 값에서 지워준다. 27 | 28 | ## :black_nib: **Review** 29 | 30 | - 여러가지 방법으로 풀 수 있는 문제 같은데 자신있는 DFS를 이용하여 문제를 풀었다. 31 | - 여러가지 알고리즘을 알아두어야겠다고 생각했다. 32 | -------------------------------------------------------------------------------- /BOJ/[7576] 토마토/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [7576] 토마토 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 정해진 배열의 크기를 넘는지 check 11 | if (nx >= 0 && nx < warehouse[0].length && ny >= 0 && ny < warehouse.length) { 12 | //토마토가 이미 익었는지 확인 13 | if (warehouse[ny][nx] == 0) { 14 | queue.add(new int[] { ny, nx }); 15 | warehouse[ny][nx] = warehouse[y][x] + 1; 16 | if (warehouse[ny][nx] > result) { 17 | result = warehouse[ny][nx]; 18 | } 19 | } 20 | } 21 | ``` 22 | - 토마토가 며칠차에 익었는지 배열에 저장하여 result를 출력하였다. 23 | - 입력 받은 초기 배열에 익은 토마토가 1로 저장 되어 있으므로 result -1 한 값을 출력한다. 24 | 25 | 26 | ## :black_nib: **Review** 27 | - 토마토가 모두 익을 때까지의 최소 날짜를 출력하는 방법에 대한 고민을 해본 문제였다. 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /BOJ/[7576] 토마토/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [7576] 토마토 2 | 3 | ## :pushpin: **Algorithm** 4 | BFS 5 | 6 | ## :round_pushpin: **Logic** 7 | ``` java 8 | private static void dayPass() { 9 | while (!todayQueue.isEmpty()) { 10 | Point cur = todayQueue.poll(); 11 | ripeTomato(cur.x, cur.y); 12 | } 13 | day++; 14 | // 하루가 지났으니 내일 큐를 오늘 큐로 넘김 15 | todayQueue.addAll(tomorrowQueue); 16 | // 내일 큐는 삭제 17 | tomorrowQueue.clear(); 18 | } 19 | ``` 20 | - 하루가 지날때마다 todayQueue에 있는 모든 위치들의 토마토를 익히고 거기서 추가되는 토마토들은 tomorrowQueue에 넣어준다. 그리고 하루가 지나면 tomorrowQueue에있는 값들을 todayQueue로 옮겨주고 tomorrowQueue는 비워준다. 21 | 22 | ## :black_nib: **Review** 23 | - 큐 2개를 사용해 문제를 푸니 메모리 효율이 너무 떨어져서 안좋은 것 같다. -------------------------------------------------------------------------------- /BOJ/[7576] 토마토/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [7576] 토마토 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | if(0<=x && x 22 | 왜냐하면 현재 행이 1번일때 (n-1, 2)스티커를 포함하면 (n-2, 2)스티커를 포함할 수 없게된다.
23 | 그래서 현재행과 다른 행의 n-1열의 스티커를 포함한 것과 n-2열의 스티커를 포함한 것 중 더 큰 점수가 현재 좌표의 최대 값이 된다. 24 | 25 | ## :black_nib: **Review** 26 | - DP는 어렵다..쉬운 문제였는데..점화식을 세우는게 아직 잘 안된다. 많이 연습해야 겠다. -------------------------------------------------------------------------------- /BOJ/[9465] 스티커/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [9465] 스티커 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 다이나믹 프로그래밍 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static int takeSticker() { 11 | 12 | for(int i = 2; i < N+2; i++) { 13 | // 1. 윗줄 스티커 - 아래줄에서 선택 14 | score[0][i] = Math.max(score[1][i-1], score[1][i-2]) + sticker[0][i]; 15 | // 2. 아래줄 스티커 - 윗줄에서 선택 16 | score[1][i] = Math.max(score[0][i-1], score[0][i-2]) + sticker[1][i]; 17 | } 18 | 19 | return Math.max(score[0][N+1], score[1][N+1]); 20 | } 21 | ``` 22 | 23 | - i번째 스티커를 떼었을 때 다음으로 뗄 수 있는 칸은 반대칸(위/아래)의 i+1, i+2번째 칸이기 때문에, 만약 i번째 스티커를 떼어낸다고 생각했을 때 바로 전 단계에 떼어낼 수 있는 스티커는 i-1, i-2번째 스티커이다. 따라서 현재 i번째 i-1, i-2번째 값 중 최대값 + 현재 스티커 점수를 더하면 해당 스티커를 떼었을 때까지의 최대값을 구할 수 있다. 24 | - i-1, i-2 인덱스에 접근해야하므로 배열의 크기를 N+2로하고, 점수를 저장하는 score 배열의 0~1인덱스는 0으로 초기화, 나머지는 스티커의 점수로 초기화 했다. 또 반복문의 시작은 2부터로 했다. 25 | 26 | ## :black_nib: **Review** 27 | 28 | - 사실 처음 풀 때는 이해가 잘 안됐는데 다시 푸니까 혼자서도 잘 풀 수 있었다 29 | -------------------------------------------------------------------------------- /BOJ/[9465] 스티커/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [9465] 스티커 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | dp[0][0] = score[0][0]; 11 | dp[1][0] = score[1][0]; 12 | 13 | if (N > 1) { 14 | dp[0][1] = dp[1][0] + score[0][1]; 15 | dp[1][1] = dp[0][0] + score[1][1]; 16 | } 17 | 18 | for (int i = 2; i < N; i++) { 19 | dp[0][i] = Math.max(dp[1][i - 2], dp[1][i - 1]) + score[0][i]; 20 | dp[1][i] = Math.max(dp[0][i - 2], dp[0][i - 1]) + score[1][i]; 21 | } 22 | 23 | System.out.println(Math.max(dp[0][N - 1], dp[1][N - 1])); 24 | ``` 25 | 26 | ``` 27 | - 위쪽 스티커를 하나 골랐다면 그 다음 고를 수 있는 스티커는 아래쪽의 다음번째 혹은 다음다음번째이다. 28 | - 위 로직을 위 아래 다 적용하여 최대값을 구해준다. 29 | 30 | 31 | ## :black_nib: **Review** 32 | - 로직 생각하기 까다로웠다.. 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ``` 41 | -------------------------------------------------------------------------------- /BOJ/[9465] 스티커/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [9465] 스티커 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | /* dp : 스티커 탐색 */ 11 | static int searchSticker() { 12 | // 초기값 설정 13 | dp[0][0] = stickers[0][0]; 14 | dp[1][0] = stickers[1][0]; 15 | 16 | for(int i=1; i 23 | 폭발 문자열과 같다면 그 문자열을 스택에서 pop()하여 없애준다. 24 | 25 | ## :black_nib: **Review** 26 | - 문자열 문제도 많이 풀어보지 못했고 스택 알고리즘도 처음 사용해봐서 많이 헤맨 문제였다. 27 | - 앞으로 문자열을 비교하고 삭제하는 문제는 스택을 사용하면 될 것같다. 28 | - 시간초과가 났었는데 출력에서 sb.insert()를 사용해서 난 문제였다. 29 | - `insert()` 는 내부에서 `System.arraycopy()`가 두 번 사용된다. (offset이후 부터 배열을 뒤로 옮겨야 하기 때문에) 하지만 `append()`는 한 번 사용되기에 `append()`가 실행시간이 더 짧다. 30 | - 당연한 이야기지만 문제를 풀 땐 생각하지 못한 부분이었다. 10000단위가 넘어가면 무조건 StringBuilder.append()를 쓰는게 좋을 것 같다. -------------------------------------------------------------------------------- /BOJ/[9935] 문자열 폭발/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [9935] 문자열 폭발 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 문자열, 스택 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | while (index < input.length()) { 11 | char current = input.charAt(index++); 12 | 13 | // 스택의 크기가 폭발 문자열의 길이 - 1보다 크거나 같은 경우, 폭발 문자열의 마지막 문자와 현재 문자가 같은 경우 문자열로 생성 14 | if (words.size() >= boomLength - 1 && lastBoomWord == current) { 15 | if (isSame(words.subList(words.size() - (boomLength - 1), words.size()))) { 16 | pop(boomLength - 1); 17 | continue; 18 | } 19 | } 20 | 21 | words.push(current); 22 | } 23 | ``` 24 | 25 | - 문자열을 탐색하면서, 스택에 넣는다. 26 | - 스택의 크기가 폭발 문자열의 길이 - 1보다 크거나 같은 경우, 폭발 문자열의 마지막 문자와 현재 탐색하는 문자가 동일한 경우에 둘의 내용을 비교한다. 27 | 28 | ## :black_nib: **Review** 29 | - 이러한 유형의 문제는 스택을 통한 풀이가 가능하다는 것은 쉽게 파악할 수 있다. 30 | - 다만 문자열에 대한 연산에 따라 메모리 초과가 발생할 수 있어서, 이를 잘 고려한 구현이 필요한 것 같다. -------------------------------------------------------------------------------- /BOJ/[9935] 문자열 폭발/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [9935] 문자열 폭발 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | Stack 6 | 7 | ## :round_pushpin: **Logic** 8 | ```java 9 | for(int i = 0; i < str.length(); i++) { 10 | stack.push(str.charAt(i)); 11 | 12 | if(str.charAt(i) == bomb.charAt(endindex) && stack.size() >= bomb.length()) { // bomb의 마지막 문자와 같으면 13 | check = true; 14 | int start = stack.size() - bomb.length(); // stack에서 탐색 시작할 위치 15 | 16 | for(int j = 0; j < endindex; j++) { 17 | if(stack.get(start+j) != bomb.charAt(j)) { // 틀린문자가 있으면 false 18 | check = false; 19 | break; 20 | } 21 | } 22 | 23 | if(check == true) { // 폭발 문자열과 일치하면 24 | for(int a = 0; a < bomb.length(); a++) { 25 | stack.pop(); 26 | } 27 | } 28 | } 29 | } 30 | ``` 31 | - 스택에 문자를 하나씩 넣으면서 만약 폭발 문자열의 끝문자와 같으면 폭발 문자열만큼 앞문자들을 검사해준다. check 변수를 통해 검사 결과를 저장하고 만약 true이면 폭발 문자열 길이만큼 스택에서 제거해준다. 32 | 33 | ## :black_nib: **Review** 34 | - print로 출력을 했었는데 시간초과가 나서 StringBuilder로 받아서 출력해주었다. StringBuilder를 열심히 활용해야겠다. 35 | -------------------------------------------------------------------------------- /BOJ/[9935] 문자열 폭발/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [9935] 문자열 폭발 2 | ## :pushpin: **Algorithm** 3 | 4 | 자료구조, 스택 5 | 6 | ## :round_pushpin: **Logic** 7 | 8 | ```java 9 | for (int i = 0; i < inputStr.length(); i++) { 10 | strStack.push(inputStr.charAt(i)); 11 | if (strStack.size() >= bombStr.length()) { 12 | for (int j = 0; j <= bombStr.length(); j++) { 13 | if (j == bombStr.length()) { 14 | removeBomb(); 15 | break; 16 | } 17 | if (strStack.get(strStack.size() - bombStr.length() + j) != bombStr.charAt(j)) { 18 | break; 19 | } 20 | } 21 | } 22 | } 23 | ``` 24 | ```java 25 | static void removeBomb() { 26 | for (int i = 0; i < bombStr.length(); i++) { 27 | strStack.pop(); 28 | } 29 | } 30 | ``` 31 | - 스택에 문자열을 하나씩 push하다 폭탄 문자열 길이 이상만큼 차면 문자열을 서로 비교한다. 32 | - 제거가 가능하다면 removeBomb()해준다. 33 | 34 | 35 | ## :black_nib: **Review** 36 | - 스택에 어떤 메소드가 있는지 찾아보게 해준 문제였다. 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /BOJ/[9935] 문자열 폭발/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 스텍 사용 4 | 5 | ## 중요 구현 로직 및 설명 6 | 7 | 스텍을 이용해 순서대로 문자를 받으면서 폭발하는 문자열이 들어오는 경우 그 문자열을 제거해준다. 8 | 9 | 1. 문자열을 순서대로 스텍에 저장한다. 10 | 2. 폭발하는 문자열의 제일 마지막 문자가 들어오는 경우 비교를 시작한다. 11 | 3. 비교 후 그 값이 유효하다면 폭발문자의 길이만큼 스텍에서 빼준다. 12 | ```java 13 | // 마지막 문자열이 같으면 14 | if (temp == boomWord.charAt(interval - 1) && result.size() >= interval) { 15 | boolean isValidate = true; 16 | for (int j = 0; j < interval - 1; j++) { 17 | if (result.get(result.size() - interval + j) != boomWord.charAt(j)) { 18 | isValidate = false; 19 | } 20 | } 21 | 22 | if (isValidate) { 23 | for (int j = 0; j < interval; j++) { 24 | result.pop(); 25 | } 26 | } 27 | } 28 | ``` 29 | 폭발문자의 마지막 문자와 같은 값이 들어오고 스텍이 충분한 크기라면 유효성 검사를 시작한다. 그 앞의 문자들도 같은 경우 폭발문자의 크기만큼 스텍에서 팝 해준다. 30 | 31 | ## 풀이 후기 32 | 33 | 자바에서 문자열을 다루는 것이 쉽지 않다고 느꼈다. 직접 구현해야 하는 부분들이 많은 것 같다. 34 | -------------------------------------------------------------------------------- /BOJ/[9935] 문자열 폭발/yeahLim/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | public class Main { 4 | public static void main(String[] args) throws IOException { 5 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 6 | String str = br.readLine(); 7 | String burst = br.readLine(); 8 | StringBuilder sb = new StringBuilder(); 9 | 10 | for (int i = 0; i < str.length(); i++) { 11 | sb.append(str.charAt(i)); 12 | if (sb.length() >= burst.length()) { 13 | boolean isTarget = true; 14 | for (int j = 0; j < burst.length(); j++) { 15 | char c1 = burst.charAt(j); 16 | char c2 = sb.charAt(sb.length() - burst.length() + j); 17 | if(c1 != c2) { 18 | isTarget = false; 19 | break; 20 | } 21 | } 22 | if(isTarget) { 23 | sb.delete(sb.length()-burst.length(), sb.length()); 24 | } 25 | } 26 | 27 | } 28 | 29 | if (sb.length() == 0) { 30 | sb.append("FRULA"); 31 | } 32 | 33 | System.out.println(sb); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CodeTree/꼬리잡기놀이/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [삼성 SW 역량테스트] 꼬리잡기놀이 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 시뮬레이션, 덱 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ## :black_nib: **Review** 10 | 11 | - 이따가 끝장내줄게! 12 | -------------------------------------------------------------------------------- /CodeTree/싸움땅/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [삼성 SW 역량테스트] 싸움땅 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 시뮬레이션 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static Queue[][] map; 11 | ``` 12 | 13 | - 무기 정보는 2차원 우선순위 큐 배열을 사용해서 저장한다. 14 | - 매번 가장 큰 무기를 가져가는 경우밖에 없기 때문이다. 15 | 16 | ```java 17 | private static void playGame() 18 | ``` 19 | 20 | - 게임은 다음과 같은 순서로 진행된다. 21 | - 플레이어는 한 명씩 차례대로 이동한다. 22 | - 이동하려는 위치에 플레이어가 없다면, 무기 정보만을 갱신한다. 23 | - 플레이어가 있다면, 싸운다. 24 | - 승자와 패자를 가린 후, 각자의 행동을 수행한다. 25 | 26 | ## :black_nib: **Review** 27 | - 하라는 것만 모두 순서에 맞게 구현하면 딱히 더 머리 쓸 건 없는 문제지만, 항상 중간에 구현을 잘못하는 부분이 생겨서 시간이 오래 걸렸다. 28 | - 지난 삼전 코테에서 풀었을 때는 답도 없이 어려워보였는데, 지금은 좀 더 금방 구현할 수 있었던 것 같다. 29 | - 최대한 돌아가도록 코드를 작성하고 리팩토링하는 방식으로 구현했는데 이를 좀 더 빠르게 할 수 있도록 하자. -------------------------------------------------------------------------------- /CodeTree/코드트리 빵/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [삼성 SW 역량테스트] 코드트리 빵 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 시뮬레이션, BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | 11 | ``` 12 | 13 | - // 편의점이랑 가장 가까운 베이스캠프 찾기 int[][] visited[x][y] = 번호 14 | // 1분/1번사람 15 | // +1/2번사람/1번 사람 이동 16 | // 전부 다 이동할때까지 반복 17 | // 한칸에 여러 사람 ㅆㄱㄴ 18 | 19 | ## :black_nib: **Review** 20 | 21 | - 22 | -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/HyeW/READMe.md: -------------------------------------------------------------------------------- 1 | # [12913] 땅따먹기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for(int cur = 1; cur < land.length; cur++){ 11 | for(int i = 0; i < COL; i++){ //현재 12 | for(int j = 0; j < COL; j++){ //이전 값 13 | // 같은 열을 연속해서 밟을 수 없다. 14 | if(i==j){ 15 | continue; 16 | } 17 | maxValue[cur][i] = Math.max(maxValue[cur][i], land[cur][i]+maxValue[cur-1][j]); 18 | } 19 | } 20 | } 21 | ``` 22 | 이전 행의 값을 보며 각 좌표에서 가질 수 있는 최대값을 구한다.
23 | 같은 열을 연속해서 밟을 수 없으니 그 부분만 조건을 걸어 처리해주었다. 24 | 25 | ## :black_nib: **Review** 26 | 27 | - 간단한 DP문제였다. 백준에서 푼 정수 삼각형하고 같은 문제였다. -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/HyeW/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | final int COL = 4; 3 | int solution(int[][] land) { 4 | int[][] maxValue = new int[land.length][COL]; //0행 : pre, 1행 : cur 5 | maxValue[0] = land[0].clone(); 6 | 7 | for(int cur = 1; cur < land.length; cur++){ 8 | for(int i = 0; i < COL; i++){ //현재 9 | for(int j = 0; j < COL; j++){ //이전 값 10 | // 같은 열을 연속해서 밟을 수 없다. 11 | if(i==j){ 12 | continue; 13 | } 14 | maxValue[cur][i] = Math.max(maxValue[cur][i], land[cur][i]+maxValue[cur-1][j]); 15 | } 16 | } 17 | } 18 | 19 | int answer = 0; 20 | for(int i = 0; i < COL; i++){ 21 | answer = Math.max(answer, maxValue[land.length-1][i]); 22 | } 23 | 24 | return answer; 25 | } 26 | } -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/asever0318/Solution_12913.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | static int[][] dp; 3 | 4 | static int solution(int[][] land) { 5 | int size = land.length; 6 | dp = new int[size][4]; 7 | 8 | for(int i =0; i < 4; i++) { 9 | dp[0][i] = land[0][i]; 10 | } 11 | 12 | for(int i = 0; i < size-1; i++) { 13 | for(int j = 0; j < 4; j++) { 14 | for(int k = 0; k < 4; k++) { 15 | if(j == k) { 16 | continue; 17 | } 18 | 19 | if(dp[i+1][k] < dp[i][j] + land[i+1][k]) { 20 | dp[i+1][k] = dp[i][j] + land[i+1][k]; 21 | } 22 | } 23 | } 24 | } 25 | 26 | return getMax(size); 27 | } 28 | 29 | static int getMax(int size) { 30 | int max = 0; 31 | 32 | for(int i = 0; i < 4; i++) { 33 | max = Math.max(max, dp[size-1][i]); 34 | } 35 | 36 | return max; 37 | } 38 | } -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [12913] 땅따먹기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int solution(int[][] land) { 11 | int[][] dp = new int[land.length][4]; 12 | 13 | dp[0] = land[0].clone(); 14 | 15 | for(int i = 1; i < land.length; i++) { 16 | for(int j = 0; j < 4; j++) { 17 | int max = 0; 18 | for(int k = 0; k < 4; k++) { 19 | if(j == k) { 20 | continue; 21 | } 22 | 23 | max = Math.max(max, dp[i - 1][k]); 24 | } 25 | dp[i][j] = max + land[i][j]; 26 | } 27 | } 28 | 29 | return Arrays.stream(dp[land.length - 1]).max().getAsInt(); 30 | } 31 | ``` 32 | 33 | - dp 배열에는 해당 땅까지 온 경우 중 가장 최적의 경우가 저장된다. 34 | - 그 다음 row를 볼때는 윗 row에서 같은 coloum을 제외하고 가장 큰 값을 골라 현재 칸의 값을 더해주어 dp배열에 저장해준다. 35 | 36 | ## :black_nib: **Review** 37 | 38 | - Bottom-up 방식으로 쉽게 풀 수 있는 DP 문제였다. 39 | -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | class Solution { 3 | int solution(int[][] land) { 4 | int[][] dp = new int[land.length][4]; 5 | 6 | dp[0] = land[0].clone(); 7 | 8 | for(int i = 1; i < land.length; i++) { 9 | for(int j = 0; j < 4; j++) { 10 | int max = 0; 11 | for(int k = 0; k < 4; k++) { 12 | if(j == k) { 13 | continue; 14 | } 15 | 16 | max = Math.max(max, dp[i - 1][k]); 17 | } 18 | dp[i][j] = max + land[i][j]; 19 | } 20 | } 21 | 22 | return Arrays.stream(dp[land.length - 1]).max().getAsInt(); 23 | } 24 | } -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [12913] 땅따먹기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | for (let i = 1; i < n; i++) { 11 | cur = land[i]; 12 | for (let j = 0; j < 4; j++) { 13 | let max = 0; 14 | for (let k = 0; k < 4; k++) { 15 | // 같은 줄을 선택하는 경우는 무시 16 | if (j === k) { 17 | continue; 18 | } 19 | if (max < prev[k]) { 20 | max = prev[k]; 21 | } 22 | } 23 | cur[j] += max; 24 | } 25 | // 현재 배열을 이전 배열로 이동 26 | prev = cur; 27 | } 28 | ``` 29 | 30 | - 행별로 내려오면서 바로 위와 같은 줄을 선택하는 경우를 제외하고 가장 큰 값을 더해준다. 31 | 32 | ## :black_nib: **Review** 33 | 34 | - 백준에서 풀었던 RGB거리 문제와 비슷한 유형의 문제라서 금방 풀이방법을 생각할 수 있었다. -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/ksg2388/Solution.js: -------------------------------------------------------------------------------- 1 | function solution(land) { 2 | let n = land.length; 3 | let prev = land[0]; 4 | let cur = []; 5 | 6 | for (let i = 1; i < n; i++) { 7 | cur = land[i]; 8 | for (let j = 0; j < 4; j++) { 9 | let max = 0; 10 | for (let k = 0; k < 4; k++) { 11 | // 같은 줄을 선택하는 경우는 무시 12 | if (j === k) { 13 | continue; 14 | } 15 | if (max < prev[k]) { 16 | max = prev[k]; 17 | } 18 | } 19 | cur[j] += max; 20 | } 21 | // 현재 배열을 이전 배열로 이동 22 | prev = cur; 23 | } 24 | return Math.max(...cur); 25 | } -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [12913] 땅따먹기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 초기값 설정 11 | dp[0] = land[0].clone(); 12 | 13 | for (int i = 1; i < n; i++) { 14 | for (int j = 0; j < 4; j++) { 15 | dp[i][j] = land[i][j] + getMaxValue(i, j); 16 | } 17 | } 18 | ``` 19 | 20 | - 각 원소마다 자기의 값(`land[i][j]`)과 그 전 행 중에 가장 큰 값(`getMaxValue(i, j)`)을 더한다. 21 | 22 | ```java 23 | /* 같은 열에서 최대값 구하기 */ 24 | public int getMaxValue(int i, int j) { 25 | int max = 0; 26 | for (int k = 0; k < 4; k++) { 27 | if (j == k) continue; 28 | max = Math.max(max, dp[i-1][k]); 29 | } 30 | return max; 31 | } 32 | ``` 33 | 34 | - 현재 열과 같은 열의 값은 제외한 값 중에서 최대값을 반환한다. 35 | 36 | ## :black_nib: **Review** 37 | 38 | - only dp문제는 언제나 재밌다 39 | -------------------------------------------------------------------------------- /Programmers/[12913] 땅따먹기/yeahLim/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | static int[][] dp; 3 | int solution(int[][] land) { 4 | int n = land.length; 5 | dp = new int[n][4]; 6 | // 초기값 설정 7 | dp[0] = land[0].clone(); 8 | 9 | for (int i = 1; i < n; i++) { 10 | for (int j = 0; j < 4; j++) { 11 | dp[i][j] = land[i][j] + getMaxValue(i, j); 12 | } 13 | } 14 | 15 | int maxScore = 0; 16 | 17 | for (int i = 0; i < 4; i++) { 18 | maxScore = Math.max(maxScore, dp[n-1][i]); 19 | } 20 | 21 | return maxScore; 22 | } 23 | 24 | /* 같은 열에서 최대값 구하기 */ 25 | public int getMaxValue(int i, int j) { 26 | int max = 0; 27 | for (int k = 0; k < 4; k++) { 28 | if (j == k) continue; 29 | max = Math.max(max, dp[i-1][k]); 30 | } 31 | return max; 32 | } 33 | } -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [12938] 최고의 집합 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 최고의 집합 조건 10 | 1. 각 원소의 합이 S가 되는 수의 집합 11 | 2. 각 원소의 곱이 최대가 되는 집합 12 | 13 | 1를 만족하는 상황에서 2를 만족하는 집합은 원소의 차이가 나지않는 수들로 이루어져 있다.
14 | 15 | ```java 16 | int avg = s/n; 17 | ``` 18 | 그래서 `전체 값/원소 수`를 구해 원소가 가질 수 있는 최소 값을 구한다. 19 | 20 | ```java 21 | if(avg == 0){ 22 | return new int[]{-1}; 23 | } 24 | ``` 25 | 만약 평균이 0이 나오면 S를 n개의 수로 나눌 수 없다는 의미로 -1을 리턴한다. 26 | 27 | ```java 28 | int remainCnt = s%n; 29 | int index = 0; 30 | for(int i = 0; i < n-remainCnt; i++){ 31 | answer[index++] = avg; 32 | } 33 | for(int i = 0; i < remainCnt; i++){ 34 | answer[index++] = avg+1; 35 | } 36 | ``` 37 | n개의 수가 최소값을 나눠가지고 남은 수를 원소에게 +1씩 해준다.
38 | 그러면 원소들끼리 차이가 최소가 되는 집합을 구할 수 있다. 39 | 40 | ## :black_nib: **Review** 41 | 42 | - 처음에 s/n을 평균이라고 했을 때 평균값을 가지고 하면 될 것같았는데 확신도 없었고 로직을 어떻게 구현할지 고민했다. 하지만 손으로 한번 직접 값을 구해보니 문제와 로직이 정리되면서 금방 풀 수 있었다. 손으로 값을 구하는 작업이 중요하다는 걸 또 다시 한번 깨달았다. -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/HyeW/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public int[] solution(int n, int s) { 4 | int[] answer = new int[n]; 5 | 6 | int avg = s/n; 7 | 8 | if(avg == 0){ 9 | return new int[]{-1}; 10 | } 11 | 12 | int remainCnt = s%n; 13 | int index = 0; 14 | for(int i = 0; i < n-remainCnt; i++){ 15 | answer[index++] = avg; 16 | } 17 | for(int i = 0; i < remainCnt; i++){ 18 | answer[index++] = avg+1; 19 | } 20 | 21 | return answer; 22 | } 23 | } -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [12938] 최고의 집합 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int start = s / n; 11 | int remain = s % n; 12 | 13 | if (start == 0) { 14 | return new int[] {-1}; 15 | } 16 | 17 | int[] answer = new int[n]; 18 | Arrays.fill(answer, start); 19 | 20 | for (int count = 0; count < remain; count++) { 21 | answer[n - 1 - count]++; 22 | } 23 | ``` 24 | 25 | - 먼저 주어진 숫자를 나눈 몫과 나머지를 기억한다. 26 | - 몫이 0이라면 애초에 자연수 n개로 s를 만들지 못한다는 의미이다. 27 | - 그렇지 않다면 일단 자연수 n개로 이뤄진 최고의 집합을 몫으로 세팅한다. (ex. start = 2, n = 4 -> {2, 2, 2, 2}) 28 | - 이후 남은 나머지만큼, 최고의 집합의 맨 뒤 인덱스부터 + 1씩 증가시킨다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 처음 아이디어는 중복조합을 사용하려 했다. 숫자 범위가 커서 시간 초과가 발생했고, 숫자가 큰 만큼 최대한 빠르게 해결하려면 주어진 숫자를 나누어야 할 것 같았다. 33 | - n과 s를 나누다보니 규칙이 보였고, 구현은 금방 했다. 34 | -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/SUbbb/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | class Solution { 4 | // n = 4, s = 9 5 | // start = 2; 6 | // remain = 1; 7 | // answer = 2(start), 2(start), 2(start), 3(start + 1); 8 | public int[] solution(int n, int s) { 9 | int start = s / n; 10 | int remain = s % n; 11 | 12 | if (start == 0) { 13 | return new int[] {-1}; 14 | } 15 | 16 | int[] answer = new int[n]; 17 | Arrays.fill(answer, start); 18 | 19 | for (int count = 0; count < remain; count++) { 20 | answer[n - 1 - count]++; 21 | } 22 | 23 | return answer; 24 | } 25 | } -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [12938] 최고의 집합 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | class Solution { 11 | static int[] solution(int n, int s) { 12 | 13 | if(n > s) { 14 | return new int[] {-1}; 15 | } 16 | return getAnswer(n, s); 17 | } 18 | 19 | static int[] getAnswer(int n, int s) { 20 | int[] ans = new int[n]; 21 | 22 | // 1. n/s한 값을 집합의 원소로 나눠갖는다. 23 | for(int i = 0; i < n; i++) { 24 | ans[i] = s/n; 25 | } 26 | 27 | // 2. n/s한 나머지를 1씩 나눠갖는다. 28 | for(int i = n-1, j = 0; i < 0 || j < s%n; i--, j++) { 29 | ans[i]++; 30 | } 31 | 32 | return ans; 33 | } 34 | } 35 | ``` 36 | 37 | - s가 n보다 작은 경우는 나누어도 1보다 작기 때문에 자연수 집합으로 이루어진 최고의 집합을 만들 수 없다. 따라서 s가 n보다 작을 때는 -1이 담긴 배열을 반환한다. 38 | - 최고의 집합은 s를 n으로 나눈 몫 n개를 원소로 가지고 s를 n으로 나눈 나머지를 원소들이 1씩 나눠가지면 된다. 39 | - 곱이 가장 큰 집합은 편차가 작은 집합이기 때문에 해당 로직이 가능하다. 40 | 41 | ## :black_nib: **Review** 42 | 43 | - 직접 예제를 써보면서 푸니까 빨리 해결할 수 있었다. 44 | -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/asever0318/Solution_12938.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | static int[] solution(int n, int s) { 3 | 4 | if(n > s) { 5 | return new int[] {-1}; 6 | } 7 | return getAnswer(n, s); 8 | } 9 | 10 | static int[] getAnswer(int n, int s) { 11 | int[] ans = new int[n]; 12 | 13 | // 1. n/s한 값을 집합의 원소로 나눠갖는다. 14 | for(int i = 0; i < n; i++) { 15 | ans[i] = s/n; 16 | } 17 | 18 | // 2. n/s한 나머지를 1씩 나눠갖는다. 19 | for(int i = n-1, j = 0; i < 0 || j < s%n; i--, j++) { 20 | ans[i]++; 21 | } 22 | 23 | return ans; 24 | } 25 | } -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [12938] 최고의 집합 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | public int[] solution(int n, int s) { 11 | int[] answer = {-1}; 12 | 13 | //집합이 생길 수 없는 경우 return 14 | if(s < n) { 15 | return answer; 16 | } 17 | 18 | answer = new int[n]; 19 | Arrays.fill(answer, s / n); 20 | 21 | //나머지 만큼 순차적으로 배열의 맨 뒤에서부터 1씩 더해줌 22 | for(int i = 0; i < s % n; i++){ 23 | answer[n - i - 1]++; 24 | } 25 | 26 | return answer; 27 | } 28 | ``` 29 | 30 | - 집합의 요소들이 차이가 가장 적은 경우가 최고의 집합이라 생각하였다. 31 | - 그래서 모두가 가질 수 있는 값 중 가장 큰 값을 넣고 나머지는 공평하게 배분하였다. 32 | 33 | ## :black_nib: **Review** 34 | 35 | - EASY 36 | -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | class Solution { 3 | public int[] solution(int n, int s) { 4 | int[] answer = {-1}; 5 | 6 | //집합이 생길 수 없는 경우 return 7 | if(s < n) { 8 | return answer; 9 | } 10 | 11 | answer = new int[n]; 12 | Arrays.fill(answer, s / n); 13 | 14 | //나머지 만큼 순차적으로 배열의 맨 뒤에서부터 1씩 더해줌 15 | for(int i = 0; i < s % n; i++){ 16 | answer[n - i - 1]++; 17 | } 18 | 19 | return answer; 20 | } 21 | } -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [12938] 최고의 집합 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | let mod = Math.floor(s / n); 11 | let remider = s % n; 12 | 13 | for (let i = 0; i < n; i++) { 14 | answer.push(mod); 15 | } 16 | ``` 17 | 18 | - 입력받은 수의 몫과 나머지를 저장해둔다. 19 | - 이후 `answer` 배열에 몫을 n개 만큼 저장한다. 20 | 21 | ```javascript 22 | // 나머지들을 1씩 분배 23 | if (remider !== 0) { 24 | for (let i = 0; i < remider; i++) { 25 | answer[answer.length - 1 - i]++; 26 | } 27 | } 28 | ``` 29 | 30 | - 이후 나머지들을 배열의 뒤쪽부터 1씩 분배해준다. 31 | 32 | ## :black_nib: **Review** 33 | 34 | - 주어진 테스트 케이스와 다른 경우 2가지 정도를 테스트해보니 규칙이 보여서 그대로 구현했더니 정답이었다. -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/ksg2388/Solution.js: -------------------------------------------------------------------------------- 1 | function solution(n, s) { 2 | var answer = []; 3 | 4 | if (n > s) { 5 | return [-1]; 6 | } 7 | 8 | let mod = Math.floor(s / n); 9 | let remider = s % n; 10 | 11 | for (let i = 0; i < n; i++) { 12 | answer.push(mod); 13 | } 14 | 15 | // 나머지들을 1씩 분배 16 | if (remider !== 0) { 17 | for (let i = 0; i < remider; i++) { 18 | answer[answer.length - 1 - i]++; 19 | } 20 | } 21 | 22 | return answer; 23 | } -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [12938] 최고의 집합 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // n > s일때 11 | if (n > s) { 12 | return new int[] {-1}; 13 | } 14 | 15 | // n <= s일때 16 | for(int i = 0; i < n; i++) { 17 | bestSet[i] = s/n; 18 | } 19 | for(int i = 0; i < s % n; i++) { 20 | bestSet[i]++; 21 | } 22 | ``` 23 | 24 | - 곱들의 합이 최대일 때는 중간 숫자들이 집합일 때이다. 따라서 최대한 균등하게 나누기 위해, n의 개수만큼 s/n을 각각의 원소에 대입한다. 그리고 나누고 나머지인 값들을 원소 하나에 1씩 더해준다. 25 | 26 | ## :black_nib: **Review** 27 | 28 | - 처음에는 중간값들의 곱이 최대값임을 알아차렸지만, 수학적으로 풀지 않고 중복 조합을 이용하여 풀었지만, 시간 초과가 나는 바람에 위와 같이 구현했다. 29 | -------------------------------------------------------------------------------- /Programmers/[12938] 최고의 집합/yeahLim/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public int[] solution(int n, int s) { 5 | 6 | /* n > s일때 */ 7 | if (n > s) { 8 | return new int[] {-1}; 9 | } 10 | 11 | /* n <= s일때 */ 12 | int [] bestSet = new int[n]; 13 | 14 | for(int i = 0; i < n; i++) { 15 | bestSet[i] = s/n; 16 | } 17 | 18 | for(int i = 0; i < s % n; i++) { 19 | bestSet[i]++; 20 | } 21 | 22 | Arrays.sort(bestSet); 23 | 24 | return bestSet; 25 | } 26 | } -------------------------------------------------------------------------------- /Programmers/[131130] 혼자 놀기의 달인/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [131130] 혼자 놀기의 달인 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 구한 depth의 개수가 2보다 크면 제일 앞 2개의 곱 반환 11 | if (depths.size() >= 2) { 12 | return depths.get(0) * depths.get(1); 13 | } 14 | 15 | // 1개면, 무조건 2번 상자 그룹의 상자 수는 0개이므로 0 반환 16 | return 0; 17 | ``` 18 | 19 | - DFS 수행 후 구한 depth의 개수에 따라 반환값이 달라진다. 20 | 21 | ## :black_nib: **Review** 22 | 23 | - 생각보다 쉬운 DFS 문제였다. -------------------------------------------------------------------------------- /Programmers/[131704] 택배상자/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | class Solution { 3 | public int solution(int[] order) { 4 | int answer = 0; 5 | int mainConveyerBox = 1; 6 | int idx = 0; 7 | Stack assistConveyerBelt = new Stack<>(); 8 | while(answer != order.length) { 9 | //메인 컨베이어벨트의 박스 번호가 order와 같은 경우 10 | if (order[idx] == mainConveyerBox) { 11 | mainConveyerBox++; 12 | idx++; 13 | answer++; 14 | continue; 15 | } 16 | //보조 컨베이어벨트의 박스번호가 order와 같은 경우 17 | if(!assistConveyerBelt.isEmpty() && assistConveyerBelt.peek() == order[idx]) { 18 | assistConveyerBelt.pop(); 19 | idx++; 20 | answer++; 21 | continue; 22 | } 23 | //더 이상 진행이 불가능한 경우 24 | if(mainConveyerBox == order.length) { 25 | break; 26 | } 27 | //진행 가능하다면 보조 컨베이어 벨트로 박스를 옮김 28 | assistConveyerBelt.push(mainConveyerBox++); 29 | } 30 | return answer; 31 | } 32 | } -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [142085] 디펜스 게임 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for(int e : enemy) { 11 | // 라운드의 적의 수를 넣는다. 12 | enemiesCnt.add(e); 13 | // 병사의 수를 갱신한다. 14 | n -= e; 15 | // 무적권이 남아있고 병사의 수가 없다면 무적권을 사용할 라운드를 찾는다. 16 | while(k > 0 && n < 0){ 17 | // 적의 수가 많은 라운드를 가져온다. 18 | int max = enemiesCnt.poll(); 19 | // 병사 보충 20 | n += max; 21 | // 무적권 소모 22 | k--; 23 | } 24 | // 병사가 적을 막을 수 없으면 종료한다. 25 | if(n < 0){ 26 | break; 27 | } 28 | round++; 29 | } 30 | ``` 31 | 32 | - 우선순위 큐를 사용해 준호가 이긴 라운드에 대해 처지한 적의 수를 내림차순으로 정렬한다. 33 | - 모든 병사를 다 사용했을 때 무적권을 사용할 라운드를 큐를 이용해 찾는다. 34 | - 가장 적의 수가 많은 라운드에 무적권을 쓰는게 이득이다. 35 | - 이때 무적권을 쓸 최적의 라운드를 찾기 위해선 준호가 모든 병사를 사용하고 난 이후에 찾아야한다. 36 | - 무적권을 큐에서 뽑은 라운드에 쓴다. 37 | 38 | 39 | ## :black_nib: **Review** 40 | 41 | - 적의 수가 많은 라운드에 무적권을 쓰는게 유리하기 때문에 우선순위 큐를 사용했다. -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/HyeW/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public int solution(int n, int k, int[] enemy) { 5 | int round = 0; 6 | // 적의 수가 많은 순으로 넣는다 7 | Queue enemiesCnt = new PriorityQueue<>((o1,o2)-> o2-o1); 8 | 9 | for(int e : enemy) { 10 | // 라운드의 적의 수를 넣는다. 11 | enemiesCnt.add(e); 12 | // 병사의 수를 갱신한다. 13 | n -= e; 14 | // 무적권이 남아있고 병사의 수가 없다면 무적권을 사용할 라운드를 찾는다. 15 | while(k > 0 && n < 0){ 16 | // 적의 수가 많은 라운드를 가져온다. 17 | int max = enemiesCnt.poll(); 18 | // 병사 보충 19 | n += max; 20 | // 무적권 소모 21 | k--; 22 | } 23 | // 병사가 적을 막을 수 없으면 종료한다. 24 | if(n < 0){ 25 | break; 26 | } 27 | round++; 28 | } 29 | return round; 30 | } 31 | } -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [142085] 디펜스 게임 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int index = 0; index < enemy.length; index++) { 11 | enemies.add(enemy[index]); 12 | 13 | // 막아야 하는 적 라운드 수가 무적권을 사용해서 막을 수 있는 라운드 수보다 많아지면, 그 중 가장 작은 적이 있는 라운드를 병사로 디펜스! 14 | if (enemies.size() > k) { 15 | n -= enemies.poll(); 16 | } 17 | 18 | // 만약 병사 수가 음수가 된다면, 더 이상 막을 수 없음! 19 | if (n < 0) { 20 | return index; 21 | } 22 | } 23 | ``` 24 | 25 | - 우선순위 큐를 사용해서, 가장 작은 적만을 병사로 디펜스하도록 한다. 26 | 27 | ## :black_nib: **Review** 28 | 29 | - 각 라운드에 대해서, 병사로 막거나, 무적권을 사용하거나, 막지 못하거나 하는 3가지 경우가 존재했다. 30 | - 하지만 이를 모두 확인하는 방식은 시간초과가 무조건 발생할 것 같았고, 큐를 사용하는 아이디어를 참고했다. 31 | -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/SUbbb/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.Queue; 2 | import java.util.PriorityQueue; 3 | 4 | class Solution { 5 | public int solution(int n, int k, int[] enemy) { 6 | Queue enemies = new PriorityQueue<>(); 7 | 8 | for (int index = 0; index < enemy.length; index++) { 9 | enemies.add(enemy[index]); 10 | 11 | // 막아야 하는 적 라운드 수가 무적권을 사용해서 막을 수 있는 라운드 수보다 많아지면, 그 중 가장 작은 적이 있는 라운드를 병사로 디펜스! 12 | if (enemies.size() > k) { 13 | n -= enemies.poll(); 14 | } 15 | 16 | // 만약 병사 수가 음수가 된다면, 더 이상 막을 수 없음! 17 | if (n < 0) { 18 | return index; 19 | } 20 | } 21 | 22 | return enemy.length; 23 | } 24 | } -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [142085] 디펜스 게임 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | void defense() { 11 | for (int i = 0; i < enemy.length; i++) { 12 | //남은 무적권이 없고, 남은 병사가 현재 적보다 적은 경우 13 | if(k == 0 && n < enemy[i]) { 14 | return; 15 | } 16 | 17 | //남은 무적권이 있고, 남은 병사가 현재 적보다 적은 경우 18 | if (n < enemy[i]) { 19 | usedSoldiers.add(enemy[i]); 20 | n += usedSoldiers.poll(); 21 | k--; 22 | n -= enemy[i]; 23 | continue; 24 | } 25 | 26 | //남은 병사로 현재 적을 막을 수 있는 경우 27 | usedSoldiers.add(enemy[i]); 28 | n -= enemy[i]; 29 | } 30 | } 31 | ``` 32 | 33 | - 매 라운드 마다 막은 병사의 수를 usedSoldiers(우선순위 큐)에 저장한다. 34 | - 남은 병사로 적을 막을 수 없는 라운드에 도달하면 usedSoldiers에서 맨 앞 index를 무적권을 사용해서 막은 것으로 바꾼다. 35 | - 무적권이 없는데, 더 이상 적을 막을 수 없는 경우까지 위 과정을 반복한다. 36 | 37 | ## :black_nib: **Review** 38 | 39 | - 문제의 로직을 생각하기가 다소 어려웠다. 40 | - 로직을 생각해내니 구현하는데는 오래 걸리진 않았다. 41 | -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [142085] 디펜스 게임 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 우선순위큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | enemy.slice(0, k).forEach((e) => pq.push(e)); 11 | 12 | for (let i = k; i < enemy.length; i++) { 13 | pq.push(enemy[i]); 14 | let temp = pq.pop(); 15 | if (temp + capacity > n) { 16 | return i; 17 | } 18 | capacity += temp; 19 | } 20 | ``` 21 | 22 | - 무적권의 개수만큼 라운드를 우선순위 큐에 담고 시작한다. 23 | - 이후 남은 라운드부터 시작하면서 우선순위큐에 값을 담고 가장 작은 값을 빼서 남은 병사의 수에서 빼준다. 24 | - 남은 병사의 수가 0보다 작아지면 종료한다. 25 | 26 | ## :black_nib: **Review** 27 | 28 | - 우선순위큐를 사용하지 않고 해보려고했지만 계속 시간초과가 나서 어쩔 수 없이 직접 구현하여 사용했다. 29 | - 생각보다 쉽지 않은 문제였다. 30 | -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [142085] 디펜스 게임 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int i = 0; i < enemy.length; i++) { 11 | pq.offer(enemy[i]); 12 | 13 | // 무적권 사용 개수보다 사이즈가 커질 경우 14 | if (pq.size() > k) { 15 | n -= pq.poll(); 16 | } 17 | 18 | // n의 개수 19 | if (n < 0) { 20 | return i; 21 | } 22 | } 23 | return enemy.length; 24 | } 25 | ``` 26 | 27 | - 한 라운드씩 우선순위 큐에 넣어주면서, 28 | - 무적권 사용 개수보다 큐의 크기가 커질 경우, 가장 적은 적의 수를 우선순위 큐에서 꺼내 병사의 수를 빼준다. 29 | - 위를 병사가 0보다 작을 때까지 반복해준다. 30 | 31 | - 최종적으로, 가능한 라운드의 수를 반환할 수 있게 된다. 32 | 33 | ## :black_nib: **Review** 34 | 35 | - Priority Queue를 for문에서 하나하나 넣으면서 확인하는 방법은 한번도 사용해 보지 않아서인지 생각이 나지 않았다. 앞으로 다른 문제에서도 Priority Queue를 잘 활용해봐야겠다. 36 | -------------------------------------------------------------------------------- /Programmers/[142085] 디펜스 게임/yeahLim/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public int solution(int n, int k, int[] enemy) { 5 | PriorityQueue pq = new PriorityQueue<>(); 6 | for (int i = 0; i < enemy.length; i++) { 7 | pq.offer(enemy[i]); 8 | 9 | // 무적권 사용 개수보다 사이즈가 커질 경우 10 | if (pq.size() > k) { 11 | n -= pq.poll(); 12 | } 13 | 14 | // n의 개수 15 | if (n < 0) { 16 | return i; 17 | } 18 | } 19 | return enemy.length; 20 | } 21 | } -------------------------------------------------------------------------------- /Programmers/[148653] 마법의 엘리베이터/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [148653] 마법의 엘리베이터 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 10 올라갔다가 내려가기 11 | if (curNum > 5) { 12 | storey += 10; 13 | magicStone += 10-curNum; 14 | 15 | }else if (curNum == 5) { 16 | // 5일 경우 앞자리 보기 17 | int nextNum = (storey/10)%10; 18 | if(nextNum < 5){ 19 | magicStone += curNum; 20 | }else{ 21 | storey += 10; 22 | magicStone += 5; 23 | } 24 | }else{ 25 | magicStone += curNum; 26 | } 27 | ``` 28 | 일의 자리 수 부터 하나씩 확인한다.
29 | 5보다 작을 경우엔 바로 내려가는 것이 더 적은 마법의 돌을 사용한다.
30 | 5보다 클 경우인 6일 경우 10으로 만들고 10을 한번에 내려가는 게 더 빠르기 때문에 위로 올라간다.
31 | 5일 경우엔 두 경우로 나뉜다.
32 | - 다음 자리수가 5보다 클 경우 올라가는 것이 더 적은 돌을 사용하고 33 | - 작을 경우엔 내려가는 것이 더 낫다. 34 | 35 | ## :black_nib: **Review** 36 | 37 | - 처음에 0층에서 올라가는 엘리베이터인줄 알고 잘못 풀었었다. 문제를 잘 읽자... 38 | -------------------------------------------------------------------------------- /Programmers/[148653] 마법의 엘리베이터/HyeW/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | int magicStone = 0; 3 | int minMagicStone = Integer.MAX_VALUE; 4 | 5 | public int solution(int storey) { 6 | getMinMagicStone(storey); 7 | return minMagicStone; 8 | } 9 | 10 | void getMinMagicStone(int storey) { 11 | int magicStone = 0; 12 | 13 | while (storey > 0) { 14 | int curNum = storey%10; 15 | 16 | // 10 올라갔다가 내려가기 17 | if (curNum > 5) { 18 | storey += 10; 19 | magicStone += 10-curNum; 20 | 21 | }else if (curNum == 5) { 22 | // 5일 경우 앞자리 보기 23 | int nextNum = (storey/10)%10; 24 | if(nextNum < 5){ 25 | magicStone += curNum; 26 | }else{ 27 | storey += 10; 28 | magicStone += 5; 29 | } 30 | }else{ 31 | magicStone += curNum; 32 | } 33 | // 다음 자리수 보기 34 | storey /= 10; 35 | } 36 | minMagicStone = magicStone; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /Programmers/[148653] 마법의 엘리베이터/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [148653] 마법의 엘리베이터 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 5보다 작은 경우는 그 수만큼 -버튼을 누른다. 11 | if (reminder < 5) { 12 | answer += reminder; 13 | } 14 | // 5인 경우 15 | else if (reminder == 5) { 16 | // 앞자리 숫자가 5보다 작은 경우 17 | if (checkNum < 5) { 18 | answer += reminder; 19 | } 20 | // 앞자리 숫자가 5보다 크거나 같은 경우 21 | else { 22 | answer += reminder; 23 | // 1을 올림해줌. 24 | division++; 25 | } 26 | } 27 | // 5보다 큰 경우 28 | else { 29 | answer += 10 - reminder; 30 | division++; 31 | } 32 | ``` 33 | 34 | - 숫자를 뒤에서 부터 확인한다. 35 | - 5보다 작은 경우는 그 만큼 answer에 더해주고, 5보다 큰 경우는 10에서 그 숫자를 뺸만큼 answer에 더해준다. 36 | - 그 값이 5인 경우 앞자리 수를 확인하여 앞자리 수가 5보다 작은 경우는 그 만큼 answer에 더해주고, 5보다 크거나 같은 경우는 10에서 그 숫자를 뺸만큼 answer에 더해주고 앞 자리수에 1을 더해준다. 37 | 38 | ## :black_nib: **Review** 39 | 40 | - 처음에는 BFS로 풀려고 시도했지만, 다른 방법이 있을 것 같아 고민해보다가 이 아이디어를 생각해냈다. 41 | - 이런 문제는 틀렸을 경우에 예외를 찾는 것이 쉽지않았다. 42 | -------------------------------------------------------------------------------- /Programmers/[148653] 마법의 엘리베이터/yeahLim/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | static int answer = 0; 3 | 4 | public int solution(int storey) { 5 | int length = Integer.toString(storey).length(); 6 | for(int i=0; i 수거 후 왕복 거리를 누적해서 저장한다. 40 | - 배달과 수거를 모두 마칠 때까지 반복한다. 41 | 42 | ## :black_nib: **Review** 43 | 44 | - 풀기는 빨리 풀었는데 이상한데서 시간썼다.ㅎ. IDE 안쓰고 프로그래머스에서 푸는 법 연습해야겠다.ㅎ. 45 | -------------------------------------------------------------------------------- /Programmers/[150369] 택배 배달과 수거하기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [150369] 택배 배달과 수거하기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | Stack, 그리디 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | while (dStack.length || pStack.length) { 11 | const dLength = dStack.length ? dStack[dStack.length - 1] : 0; 12 | const pLength = pStack.length ? pStack[pStack.length - 1] : 0; 13 | const length = Math.max(dLength, pLength); 14 | // 트럭의 용량만큼 택배 배달 및 수거 15 | for (let i = 0; i < cap; i++) { 16 | dStack.pop(); 17 | pStack.pop(); 18 | } 19 | answer += length * 2; 20 | } 21 | ``` 22 | 23 | - 배달해야할 상자와 수거해야할 상자 중 가장 멀리 있는 상자의 위치를 저장한다. 24 | - 이후 트럭의 용량만큼 상자들을 수거 및 배달한다. 25 | - 택배 배달과 수거가 모두 끝날때까지 반복한다. 26 | 27 | 28 | ## :black_nib: **Review** 29 | 30 | - 택배를 어떤 방식으로 수거하고 계산할지 선택하는게 중요한 문제였다. 31 | - 다른 방법으로도 풀 수 있는 문제인지 궁금하다. -------------------------------------------------------------------------------- /Programmers/[150369] 택배 배달과 수거하기/ksg2388/Solution.js: -------------------------------------------------------------------------------- 1 | function solution(cap, n, deliveries, pickups) { 2 | let answer = 0; 3 | let dStack = []; 4 | let pStack = []; 5 | 6 | // 배달해야할 택배들 저장 7 | deliveries.map((count, index) => { 8 | for (let i = 0; i < count; i++) { 9 | dStack.push(index + 1); 10 | } 11 | }) 12 | 13 | // 수거해야할 택배들 저장 14 | pickups.map((count, index) => { 15 | for (let i = 0; i < count; i++) { 16 | pStack.push(index + 1); 17 | } 18 | }) 19 | 20 | while (dStack.length || pStack.length) { 21 | const dLength = dStack.length ? dStack[dStack.length - 1] : 0; 22 | const pLength = pStack.length ? pStack[pStack.length - 1] : 0; 23 | const length = Math.max(dLength, pLength); 24 | // 트럭의 용량만큼 택배 배달 및 수거 25 | for (let i = 0; i < cap; i++) { 26 | dStack.pop(); 27 | pStack.pop(); 28 | } 29 | answer += length * 2; 30 | } 31 | 32 | return answer; 33 | } -------------------------------------------------------------------------------- /Programmers/[154540] 무인도 여행/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [154540] 무인도 여행 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | function findIsLand(map, x, y) { 11 | const queue = []; 12 | let count = +map[x][y]; 13 | map[x][y] = 'X'; 14 | queue.push([x, y]); 15 | 16 | while (queue.length) { 17 | const [cx, cy] = queue.shift(); 18 | 19 | for (let i = 0; i < 4; i++) { 20 | const nx = cx + dx[i]; 21 | const ny = cy + dy[i]; 22 | 23 | // 주변에 무인도가 없는 경우 무시 24 | if (isMapOut(nx, ny) || map[nx][ny] === 'X') continue; 25 | // 무인도가 있는 경우 큐에 추가 26 | count += +map[nx][ny]; 27 | map[nx][ny] = 'X'; 28 | queue.push([nx, ny]); 29 | } 30 | } 31 | return count; 32 | } 33 | ``` 34 | 35 | - BFS를 이용하여 주변 무인도의 식량의 합을 카운트한다. 36 | 37 | ## :black_nib: **Review** 38 | 39 | - 그냥 간단한 기본 BFS 문제였다. 40 | - BFS Master ~~ 41 | -------------------------------------------------------------------------------- /Programmers/[155651] 호텔 대실/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [155651] 호텔 대실 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 그리디 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private boolean canAssignPrevRoom(Time time) { 11 | if (!endTimes.isEmpty()) { 12 | for (int index = endTimes.size() - 1; index >= 0; index--) { 13 | if (endTimes.get(index) + 10 <= time.start) { 14 | endTimes.set(index, time.end); 15 | return true; 16 | } 17 | } 18 | } 19 | 20 | endTimes.add(time.end); 21 | return false; 22 | } 23 | ``` 24 | 25 | - 사용한 방들의 퇴실 시각을 저장한 리스트를 뒤에서부터 탐색하면서, 청소가 끝난 방을 사용할 수 있다면 사용하도록 한다. 26 | - 뒤에서부터 탐색하는 이유는, 입실 시각이 늦은 방부터 확인하기 위함이다. 27 | 28 | ## :black_nib: **Review** 29 | 30 | - 백준의 회의실 배정 문제를 풀어봤어서, 똑같은 방식인 줄 알고 정렬 기준을 퇴실 시각으로 잡아서 풀었었다. 31 | - 하지만 아무리 봐도 틀린 부분이 없는데 많은 테케를 틀려서 정렬 기준을 입실 시각으로 바꿨더니 정답이었다. 32 | - 두 개의 차이를 ChatGPT한테 물어봤는데, 입실 시각을 기준으로 정렬해야, 이전 방 사용 퇴실 시각과의 비교를 통해 최소한의 객실을 사용할 수 있다고 했다. 33 | - 이게 뭔 말인지 이해가 안된다. 34 | -------------------------------------------------------------------------------- /Programmers/[160585] 혼자서 하는 틱택토/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [160585] 혼자서 하는 틱택토 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 잘못된 경우 10 | 11 | - O개수와 X개수의 차이가 2개 이상인 경우 12 | - X개수가 O개수보다 1개 많은 경우 13 | - O, X 둘 다 틱택토를 완성한 경우 14 | - O가 이겼는데 O와 X의 개수가 같은 경우 15 | 16 | ```javascript 17 | // O의 개수가 X와 같거나 1개 더 많지 않은 경우 18 | let diff = Math.abs(oCount - xCount); 19 | 20 | if (diff > 1) { 21 | return 0; 22 | } 23 | 24 | if (xCount > oCount) { 25 | return 0; 26 | } 27 | ``` 28 | 29 | - 위 조건중 첫번째 조건 확인 30 | 31 | ```javascript 32 | // 둘 다 이긴 경우 33 | if (xEnd && oEnd) { 34 | return true; 35 | } 36 | // 선공만 이긴 경우 37 | if (oEnd && oCount <= xCount) { 38 | return true; 39 | } 40 | // 후공만 이긴 경우 41 | if (xEnd && oCount != xCount) { 42 | return true; 43 | } 44 | ``` 45 | 46 | - 위 조건중 아래 3가지 조건 확인 47 | 48 | ## :black_nib: **Review** 49 | 50 | - 단순한 구현문제였는데 코드를 깔끔하게 정리하는게 생각보다 어려웠다... 51 | -------------------------------------------------------------------------------- /Programmers/[161988] 연속 펄스 부분 수열의 합/README.md: -------------------------------------------------------------------------------- 1 | # [161988] 연속 펄스 부분 수열의 합 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DP 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | let seq1 = sequence.map((item, idx) => { 11 | if (idx % 2 === 0) { 12 | return item * -1; 13 | } 14 | return item; 15 | }); 16 | let seq2 = sequence.map((item, idx) => { 17 | if (idx % 2 === 1) { 18 | return item * -1; 19 | } 20 | return item; 21 | }); 22 | ``` 23 | 24 | - 기존의 sequence배열을 이용해 2개의 펄스배열을 만든다. 25 | 26 | ```javascript 27 | const dp1 = [seq1[0]]; 28 | const dp2 = [seq2[0]]; 29 | 30 | for (let i = 1; i < sequence.length; i++) { 31 | dp1[i] = Math.max(dp1[i - 1] + seq1[i], seq1[i]); 32 | dp2[i] = Math.max(dp2[i - 1] + seq2[i], seq2[i]); 33 | max = Math.max(dp1[i], dp2[i], max); 34 | } 35 | ``` 36 | 37 | - 점화식 => DP[N] = max(DP[N-1] + K번째 원소, K번째 원소) 38 | - 점화식을 이용하여 배열을 DP배열을 채우고 dp배열 중 가장 큰 값을 최대값에 넣는다. 39 | 40 | ## :black_nib: **Review** 41 | 42 | - 생각보다 쉽게 풀리는 문제였다. 43 | -------------------------------------------------------------------------------- /Programmers/[161988] 연속 펄스 부분 수열의 합/Solution.js: -------------------------------------------------------------------------------- 1 | function solution(sequence) { 2 | let seq1 = sequence.map((item, idx) => { 3 | if (idx % 2 === 0) { 4 | return item * -1; 5 | } 6 | return item; 7 | }); 8 | let seq2 = sequence.map((item, idx) => { 9 | if (idx % 2 === 1) { 10 | return item * -1; 11 | } 12 | return item; 13 | }); 14 | let max = Math.max(seq1[0], seq2[0]); 15 | const dp1 = [seq1[0]]; 16 | const dp2 = [seq2[0]]; 17 | 18 | for (let i = 1; i < sequence.length; i++) { 19 | dp1[i] = Math.max(dp1[i - 1] + seq1[i], seq1[i]); 20 | dp2[i] = Math.max(dp2[i - 1] + seq2[i], seq2[i]); 21 | max = Math.max(dp1[i], dp2[i], max); 22 | } 23 | 24 | return max; 25 | } 26 | -------------------------------------------------------------------------------- /Programmers/[169199] 리코쳇 로봇/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [169199] 리코쳇 로봇 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | public int getMinMove(Position start) 11 | ``` 12 | 13 | - 기본 BFS를 사용해서 목표지점까지의 최단거리를 구했다.
14 | 15 | ```java 16 | /* 로봇이 미끄러져서 도착한 위치좌표를 반환한다. */ 17 | public Position slideRobot(Position cur, int dir){ 18 | int dx = cur.x; 19 | int dy = cur.y; 20 | 21 | while(!isMapOut(dx, dy) && board[dx].charAt(dy) != 'D'){ 22 | dx += dr[dir]; 23 | dy += dc[dir]; 24 | } 25 | return new Position(dx - dr[dir], dy - dc[dir]); 26 | } 27 | ``` 28 | - 4방을 한 칸씩 움직이는 것이 아니라 벽이나 맵의 끝을 만날때까지 이동하기 때문에 29 | 이동에 대한 함수를 따로 만들어 주었다. 30 | 31 | ## :black_nib: **Review** 32 | 33 | - 이동만 슬라이드로 하는 평범한 BFS 문제였다. -------------------------------------------------------------------------------- /Programmers/[169199] 리코쳇 로봇/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [169199] 리코쳇 로봇 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | // 벽에 부딛힐 때까지 이동 11 | while (true) { 12 | if ( 13 | isMapOut(nx + dx[i], ny + dy[i]) || 14 | board[nx + dx[i]][ny + dy[i]] === 'D' 15 | ) { 16 | break; 17 | } 18 | nx += dx[i]; 19 | ny += dy[i]; 20 | } 21 | // 방문한 적이 있는 경우 무시 22 | if (visited[nx][ny]) { 23 | continue; 24 | } 25 | if (board[nx][ny] === 'G') { 26 | return; 27 | } 28 | isMove = true; 29 | visited[nx][ny] = true; 30 | queue.push([nx, ny]); 31 | ``` 32 | 33 | - 벽을 만나거나 맵 밖으로 나갈때까지 이동한다. 34 | - 이동이 끝나면 그 위치에 방문한 적이 있는지 확인하고 있는 경우는 무시한다. 35 | - 도착점에 도착하면 종료하고 아닌 경우는 계속해서 탐색한다. 36 | 37 | ## :black_nib: **Review** 38 | 39 | - 기존 BFS에서 변형된 문제였는데 생각보다 쉽지 않았다. 40 | - 인덱스 접근 에러가 많이나서 고생했다... 41 | -------------------------------------------------------------------------------- /Programmers/[169199] 리코쳇 로봇/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [169199] 리코쳇 로봇 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | while (!q.isEmpty()) { 11 | Point point = q.poll(); 12 | 13 | if (point.x == goalX && point.y == goalY) { 14 | return point.count; 15 | } 16 | 17 | // 상 18 | int i = point.x; 19 | while (i >= 0 && board[i][point.y] == '.') { 20 | i--; 21 | } 22 | if (!visited[++i][point.y]) { 23 | visited[i][point.y] = true; 24 | q.offer(new Point(i, point.y, point.count+1)); 25 | } 26 | ``` 27 | 28 | - BFS를 이용해 최소 이동 거리를 구했다. 29 | - 상/하/좌/우 움직임을 각각 따로 구했다. 30 | - 범위 끝에 달하거나, 장애물을 만날때까지 상/하/좌/우로 이동한다. 31 | - 이동한 위치에 처음 방문했다면 queue에 넣어준다. 32 | 33 | ## :black_nib: **Review** 34 | 35 | - 모든 방향을 각각 구현해주었더니 더 쉽게 풀린 것 같다. 36 | -------------------------------------------------------------------------------- /Programmers/[181188] 요격 시스템/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [181188] 요격 시스템 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private Queue targetLocations = new PriorityQueue<>(new Comparator() { 11 | @Override 12 | public int compare(int[] o1, int[] o2) { 13 | return Integer.compare(o1[1], o2[1]); 14 | } 15 | }); 16 | ``` 17 | 18 | - end를 기준으로 오름차순 정렬된 우선순위 큐 선언 19 | 20 | ```java 21 | while (!targetLocations.isEmpty()) { 22 | int[] current = targetLocations.poll(); 23 | 24 | // 큐의 peek의 start가 current의 end보다 작은 경우 계속 poll 25 | while (!targetLocations.isEmpty() && targetLocations.peek()[0] < current[1]) { 26 | targetLocations.poll(); 27 | } 28 | 29 | answer++; 30 | } 31 | ``` 32 | 33 | - 하나의 target의 end를 기준으로 잡아두고 다른 폭격을 확인한다. 34 | - 폭격 미사일의 start가 기준으로 잡아둔 target의 end 안에 있는 경우, 함께 요격할 수 있다. 35 | 36 | ## :black_nib: **Review** 37 | 38 | - 어떤 자료구조를 사용해야 할 지에 대해서 고민해보다가, 큐 ... 아니면 도저히 사용할 수 있을 게 없었다. 39 | - 근데 어떤 기준으로 정렬을 해야할 지 몰랐는데, 주어진 정보 2개 중 하나를 사용하면 되는 거였다... 40 | -------------------------------------------------------------------------------- /Programmers/[181188] 요격 시스템/SUbbb/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | // end를 기준으로 오름차순 정렬 5 | private Queue targetLocations = new PriorityQueue<>(new Comparator() { 6 | @Override 7 | public int compare(int[] o1, int[] o2) { 8 | return Integer.compare(o1[1], o2[1]); 9 | } 10 | }); 11 | 12 | public int solution(int[][] targets) { 13 | for (int[] target : targets) { 14 | targetLocations.add(target); 15 | } 16 | 17 | int answer = 0; 18 | 19 | while (!targetLocations.isEmpty()) { 20 | int[] current = targetLocations.poll(); 21 | 22 | // 큐의 peek의 start가 current의 end보다 작은 경우 계속 poll 23 | while (!targetLocations.isEmpty() && targetLocations.peek()[0] < current[1]) { 24 | targetLocations.poll(); 25 | } 26 | 27 | answer++; 28 | } 29 | 30 | return answer; 31 | } 32 | } -------------------------------------------------------------------------------- /Programmers/[181188] 요격 시스템/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | class Solution { 3 | public int solution(int[][] targets) { 4 | int answer = 0; 5 | 6 | Arrays.sort(targets, (o1, o2) -> o1[0] - o2[0]); 7 | 8 | int end = targets[0][1]; 9 | 10 | for (int i = 1; i < targets.length; i++) { 11 | if (end <= targets[i][0]) { 12 | end = targets[i][1]; 13 | answer++; 14 | continue; 15 | } 16 | 17 | if (end > targets[i][1]) { 18 | end = targets[i][1]; 19 | } 20 | } 21 | 22 | //마지막 요격 미사일 발사는 위 조건에서 걸리지 않으니 answer + 1 return 23 | return answer + 1; 24 | } 25 | } -------------------------------------------------------------------------------- /Programmers/[181188] 요격 시스템/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [181188] 요격 시스템 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | targets.sort((e1, e2) => { 11 | return e1[1] - e2[1]; 12 | }); 13 | ``` 14 | 15 | - 요격해야할 구간을 끝나는 시간을 기준으로 오름차순으로 정렬한다. 16 | 17 | ```javascript 18 | for (let i = 1; i < targets.length; i++) { 19 | // 범위 밖인 경우 20 | if (end <= targets[i][0]) { 21 | start = targets[i][0]; 22 | end = targets[i][1]; 23 | count++; 24 | continue; 25 | } 26 | } 27 | ``` 28 | 29 | - 다음 구간을 확인하면서 이전구간의 범위 안에 있는 경우는 계속 다음 구간을 확인한다. 30 | - 범위 밖인 경우 요격 수를 1증가시키고 다시 시작과 끝 범위를 정하고 탐색한다. 31 | 32 | ## :black_nib: **Review** 33 | 34 | - 정렬해서 푼다는 것을 쉽게 떠올리지 못했다. 35 | - 정렬만 하면 쉽게 풀리는 문제라서 좋았다. 36 | -------------------------------------------------------------------------------- /Programmers/[181188] 요격 시스템/ksg2388/Solution.js: -------------------------------------------------------------------------------- 1 | function solution(targets) { 2 | targets.sort((e1, e2) => { 3 | return e1[1] - e2[1]; 4 | }); 5 | let start = targets[0][0], 6 | end = targets[0][1]; 7 | let count = 1; 8 | 9 | for (let i = 1; i < targets.length; i++) { 10 | // 범위 밖인 경우 11 | if (end <= targets[i][0]) { 12 | start = targets[i][0]; 13 | end = targets[i][1]; 14 | count++; 15 | continue; 16 | } 17 | } 18 | return count; 19 | } 20 | -------------------------------------------------------------------------------- /Programmers/[181188] 요격 시스템/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [181188] 요격 시스템 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 우선순위 큐, 그리디 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | PriorityQueue missile = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]); 11 | ``` 12 | 13 | - 이 코드의 핵심은 미사일 범위의 끝을 기준으로 오름차순으로 정렬하는 것이다. 14 | 15 | ```java 16 | while (!missile.isEmpty()) { 17 | baseMs = missile.poll(); 18 | count++; 19 | 20 | // 기준 미사일의 범위와 겹치는지 확인 21 | while(!missile.isEmpty()) { 22 | comparedMs = missile.peek(); 23 | // 겹치는 경우 24 | if (comparedMs[0] < baseMs[1]) { 25 | missile.poll(); 26 | } 27 | // 아닌 경우 28 | else { 29 | break; 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | - 기준 미사일을 기준으로 미사일을 하나하나 비교한다. 36 | - 겹치지 않은 미사일이 나오면 비교를 멈추고, 그 미사일을 기준 미사일로 변경한다. 37 | - 기준 미사일의 개수만큼 count값을 +1 해준다. 38 | 39 | ## :black_nib: **Review** 40 | 41 | - 이런 그리디 문제는 정렬이 핵심이라는 것을 페어에게 배운 적이 있다. 그 부분을 고려하여 풀었더니, 바로 정답나와버려서 기분이 좋았다. 42 | -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [42584] 주식가격 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int current = 0; current < N; current++) { 11 | answer[current] = 0; 12 | 13 | for (int next = current + 1; next < N; next++) { 14 | // 다음 초가 있으면 일단 최소 1초동안은 가격이 떨어지지 않은 것 15 | answer[current]++; 16 | 17 | // 가격이 떨어지면 종료 18 | if (prices[next] < prices[current]) { 19 | break; 20 | } 21 | } 22 | } 23 | ``` 24 | 25 | - 현재 가격보다 다음 주식가격이 더 크면 시간 증가를 멈춘다. 26 | 27 | ## :black_nib: **Review** 28 | 29 | - 알고리즘 분류가 스택/큐로 되어있어서.. 자료구조를 활용하려 했는데, 깔끔한 방법이 떠오르지 않았다. 30 | - 단순 구현으로도 가능할 것 같아서 구현했다! -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/SUbbb/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public int[] solution(int[] prices) { 5 | int N = prices.length; 6 | int[] answer = new int[N]; 7 | 8 | for (int current = 0; current < N; current++) { 9 | answer[current] = 0; 10 | 11 | for (int next = current + 1; next < N; next++) { 12 | // 다음 초가 있으면 일단 최소 1초동안은 가격이 떨어지지 않은 것 13 | answer[current]++; 14 | 15 | // 가격이 떨어지면 종료 16 | if (prices[next] < prices[current]) { 17 | break; 18 | } 19 | } 20 | } 21 | 22 | return answer; 23 | } 24 | } -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [42584] 주식가격 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | public int[] solution(int[] prices) { 11 | int[] answer = new int[prices.length]; 12 | 13 | // 마지막은 무조건 0이니까 prices 길이 -1까지만 탐색하기 14 | for(int i = 0; i < prices.length-1; i++){ 15 | for(int j = i+1; j < prices.length; j++){ 16 | answer[i]++; // 가격이 떨어지는데 무조건 1초이상 걸리기 때문에 먼저 ++해줌 17 | 18 | if(prices[i] > prices[j]){ // 만약 주가가 내리면 멈추기 19 | break; 20 | } 21 | } 22 | } 23 | 24 | return answer; 25 | } 26 | ``` 27 | 28 | - 마지막 요소는 반드시 0이 되는 것을 알 수 있기 때문에 마지막 요소 전 요소까지만 탐색한다. 29 | - 현재 주가(i)보다 주가(j)가 하락할 때까지 answer++ 해준다. 30 | 31 | ## :black_nib: **Review** 32 | 33 | - 아무리 생각해도 스택으로 풀 방법이 생각나지 않았다.. 스택을 사용하지 않고 간단하게 풀 수 있는 문제였다. 하지만 스택으로도 다시 풀어보고싶다! 34 | -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/asever0318/Solution_42584.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public int[] solution(int[] prices) { 5 | int[] answer = new int[prices.length]; 6 | 7 | // 마지막은 무조건 0이니까 prices 길이 -1까지만 탐색하기 8 | for(int i = 0; i < prices.length-1; i++){ 9 | for(int j = i+1; j < prices.length; j++){ 10 | answer[i]++; // 가격이 떨어지는데 무조건 1초이상 걸리기 때문에 먼저 ++해줌 11 | 12 | if(prices[i] > prices[j]){ // 만약 주가가 내리면 멈추기 13 | break; 14 | } 15 | } 16 | } 17 | 18 | return answer; 19 | } 20 | } 21 | 22 | // 가격이 떨어지지 않은 시간을 저장 -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [42584] 주식가격 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | public int[] solution(int[] prices) { 11 | int[] answer = new int[prices.length]; 12 | 13 | for (int i = 0; i < prices.length; i++) { 14 | for (int j = i + 1; j < prices.length; j++) { 15 | answer[i]++; 16 | if (prices[i] > prices[j]) 17 | break; 18 | 19 | } 20 | } 21 | 22 | return answer; 23 | } 24 | ``` 25 | 26 | - 2중 for문을 돌면서 해당 주식이 언제까지 상승 하는지 계산한다. 27 | 28 | ## :black_nib: **Review** 29 | 30 | - stack으로 풀라고 만든 문제임을 알았으나 잘 되지 않아서 단순 구현으로 해결하였다. 31 | - 단순 구현으로 풀 때 시간 복잡도는 O(n^2)이다. 따라서 최악의 경우 시간 초과가 날 수 도 있으나, 위 문제는 그런 최악의 경우를 만드는 것이 불가능한 문제이다. 32 | -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | class Solution { 3 | public int[] solution(int[] prices) { 4 | int[] answer = new int[prices.length]; 5 | 6 | for (int i = 0; i < prices.length; i++) { 7 | for (int j = i + 1; j < prices.length; j++) { 8 | answer[i]++; 9 | if (prices[i] > prices[j]) 10 | break; 11 | 12 | } 13 | } 14 | 15 | return answer; 16 | } 17 | } -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [42584] 주식가격 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현, 스텍 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int i = 0; i < length; i++) { 11 | // 주식의 가격이 떨어진지 확인 12 | while (!stack.isEmpty() && stack.peek().price > prices[i]) { 13 | priceData temp = stack.pop(); 14 | answer[temp.index] = i - temp.index; 15 | } 16 | stack.push(new priceData(prices[i], i)); 17 | } 18 | ``` 19 | 20 | - 스텍을 이용하여 새로 들어온 주식의 가격이 스텍 가장 위의 가격보다 작은 경우 가격이 떨어지는 경우이므로 스텍에서 `pop`하고 시간을 계산하여 `answer`에 저장한다. 21 | - 이 과정에서 스텍에서 `pop` 후 그 다음값도 작은 경우 계속해서 `pop`해준다. 22 | 23 | ```java 24 | for (priceData data: stack) { 25 | answer[data.index] = length - 1 - data.index; 26 | } 27 | ``` 28 | 29 | - 이후 남아있는 주식의 값들을 계산하여 저장해준다. 30 | 31 | ## :black_nib: **Review** 32 | 33 | - 알고리즘 분류가 스텍으로 되어있어서 스텍을 사용하여 문제를 해결하였다. 34 | - 시간을 어떤 방식으로 저장할지가 관건이었다. 35 | -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [42584] 주식가격 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int i = 0; i < prices.length; i++) { 11 | for (int j = i+1; j < prices.length; j++) { 12 | result[i]++; 13 | if (prices[i] > prices[j]) { 14 | break; 15 | } 16 | } 17 | } 18 | ``` 19 | 20 | - 현재 가격보다 더 떨어질 때까지 시간 +1을 해준다. 21 | 22 | ## :black_nib: **Review** 23 | 24 | - 처음에 스택 문제인 것을 파악했으나, 스택으로 풀려니 더 복잡해서 그냥 구현으로 풀었다! -------------------------------------------------------------------------------- /Programmers/[42584] 주식가격/yeahLim/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | 5 | public int[] solution(int[] prices) { 6 | int[] result = new int[prices.length]; 7 | for (int i = 0; i < prices.length; i++) { 8 | for (int j = i+1; j < prices.length; j++) { 9 | result[i]++; 10 | if (prices[i] > prices[j]) { 11 | break; 12 | } 13 | } 14 | } 15 | 16 | return result; 17 | } 18 | } -------------------------------------------------------------------------------- /Programmers/[42860] 조이스틱/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [42860] 조이스틱 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 그리디 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | for (int index = 0; index < length; index++) { 11 | answer += convertCost(name.charAt(index)); 12 | 13 | int next = index + 1; 14 | // 연속되는 A 갯수 확인 15 | while (next < length && name.charAt(next) == 'A') { 16 | next++; 17 | } 18 | 19 | // 순서대로 가는 것과, 뒤로 돌아가는 것 중 이동수가 적은 것을 선택 20 | move = Math.min(move, index * 2 + length - next); 21 | // BBBBAAAAAAAB 와 같이, 처음부터 뒷부분을 먼저 입력하는 것이 더 빠른 경우까지 고려하려면 아래의 코드가 필요 22 | move = Math.min(move, (length - next) * 2 + index); 23 | } 24 | ``` 25 | 26 | - 제일 첫번째 위치부터 변환을 수행하고, 이후 등장하는 연속된 A의 개수를 구한다. 27 | - 해당 위치에서 앞으로 가는 경우와 뒤로 가는 경우를 나눠 이동하는 최소의 경우를 구한다. 28 | 29 | ## :black_nib: **Review** 30 | 31 | - 그래프 풀이도 고민해보고, 다른 구현 방식도 고려해봤는데 감이 잡히지 않아 정답을 참고했는데, 잘 이해가 되지 않는다. 32 | -------------------------------------------------------------------------------- /Programmers/[42860] 조이스틱/asever0318/Solution_42860.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | static int solution(String name) { 3 | char[] str = name.toCharArray(); 4 | int sum = 0; 5 | 6 | // 1. 각 문자의 최소 조작 횟수 구하기 7 | for(int i = 0; i < str.length; i++) { 8 | if(str[i] == 'A') { 9 | continue; 10 | } 11 | sum += Math.min(Math.abs(str[i]-'A'), Math.abs('Z'-str[i]+1)); 12 | } 13 | 14 | // 2. 각 문자로 이동하는 최소 횟수 15 | int move = str.length-1; // 최대 이동 횟수는 str-1번 16 | 17 | for(int i = 0; i < str.length-1; i++) { 18 | // 만약 다음 문자가 'A'이면 연속된 A길이 구하기 19 | if(str[i+1] == 'A') { 20 | int j = i+1; 21 | while(j < str.length && str[j] == 'A') { 22 | j++; 23 | } 24 | 25 | move = Math.min(move, (i*2+(str.length-j))); 26 | move = Math.min(move, (str.length-j)*2+i); 27 | } 28 | } 29 | 30 | return sum + move; 31 | } 32 | } -------------------------------------------------------------------------------- /Programmers/[42860] 조이스틱/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [17683] 방금그곡 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 문자열 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | public int solution(String name) { 11 | int answer = 0; 12 | int length = name.length(); 13 | 14 | int index; 15 | int move = length - 1; 16 | 17 | for(int i = 0; i < name.length(); i++){ 18 | answer += Math.min(name.charAt(i) - 'A', 'Z' - name.charAt(i) + 1); 19 | 20 | index = i + 1; 21 | while(index < length && name.charAt(index) == 'A'){ 22 | index++; 23 | } 24 | 25 | move = Math.min(move, i * 2 + length - index); 26 | 27 | move = Math.min(move, (length - index) * 2 + i); 28 | } 29 | return answer + move; 30 | } 31 | ``` 32 | - 조이스틱을 상하로 움직이는 경우는 Math.min을 활용하였다. 33 | - 더 적은 이동 횟수를 가지는 방향을 찾아 그 방향으로 이동하며 로직을 수행한다. 34 | 35 | ## :black_nib: **Review** 36 | 37 | - 사실 답을 봐도 잘 이해가 되지 않는다. 38 | -------------------------------------------------------------------------------- /Programmers/[42860] 조이스틱/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int solution(String name) { 3 | int answer = 0; 4 | int length = name.length(); 5 | 6 | int index; // 다음 값들을 확인할 때 사용 7 | int move = length - 1; // 좌우 움직임 수를 체크 8 | 9 | for(int i = 0; i < name.length(); i++){ 10 | answer += Math.min(name.charAt(i) - 'A', 'Z' - name.charAt(i) + 1); 11 | 12 | index = i + 1; 13 | while(index < length && name.charAt(index) == 'A'){ 14 | index++; 15 | } 16 | 17 | move = Math.min(move, i * 2 + length - index); 18 | 19 | move = Math.min(move, (length - index) * 2 + i); 20 | } 21 | return answer + move; 22 | } 23 | } -------------------------------------------------------------------------------- /Programmers/[42860] 조이스틱/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [42860] 조이스틱 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 그리디 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | let minMove = name.length - 1; 11 | for (let i = 1; i < name.length; i++) { 12 | if (name[i] === 'A') { 13 | for (j = i + 1; j < name.length; j++) { 14 | if (name[j] !== 'A') { 15 | break; 16 | } 17 | } 18 | const left = i - 1; // A가 나오지 직전까지 19 | const right = name.length - j; 20 | minMove = Math.min(minMove, left > right ? left + right * 2 : left * 2 + right); 21 | 22 | i = j; 23 | } 24 | } 25 | ``` 26 | 27 | - A가 뭉쳐있는 지역을 만나면 그 지역을 지나지 않고 모든 위치를 탐색하는 경우가 최소가 되는 경우를 구해준다. 28 | 29 | ## :black_nib: **Review** 30 | 31 | - 그리디 알고리즘이라고 분류되어 있어서 그리디로 풀려고 했지만 계속 실패했다.... 알고보니 문제 테스트케이스가 추가되어 더이상 그리디로 푸는 문제가 아니었다. 32 | - 그래서 풀이 방법을 참고했는데 어려운 문제였다. -------------------------------------------------------------------------------- /Programmers/[42860] 조이스틱/ksg2388/Solution.js: -------------------------------------------------------------------------------- 1 | function solution(name) { 2 | let sum = 0; 3 | let j = 0; 4 | for (let i = 0; i < name.length; i++) { 5 | let diff = name[i].charCodeAt() - 'A'.charCodeAt(); 6 | sum += diff > 13 ? 26 - diff : diff; 7 | } 8 | 9 | let minMove = name.length - 1; 10 | for (let i = 1; i < name.length; i++) { 11 | if (name[i] === 'A') { 12 | for (j = i + 1; j < name.length; j++) { 13 | if (name[j] !== 'A') { 14 | break; 15 | } 16 | } 17 | const left = i - 1; // A가 나오지 직전까지 18 | const right = name.length - j; 19 | minMove = Math.min(minMove, left > right ? left + right * 2 : left * 2 + right); 20 | 21 | i = j; 22 | } 23 | } 24 | return sum + minMove; 25 | } 26 | -------------------------------------------------------------------------------- /Programmers/[49994] 방문 길이/ksg2388/Main.js: -------------------------------------------------------------------------------- 1 | function solution(dirs) { 2 | let cur = [0, 0]; 3 | let coordinates = { 4 | x: 0, 5 | y: 0, 6 | }; 7 | 8 | let result = dirs.split('').reduce((acc, dir) => { 9 | let [x, y] = cur; 10 | 11 | if (dir === 'R') { 12 | if (y < 5) { 13 | acc.add(`${x},${y + 0.5}`); 14 | y += 1; 15 | } 16 | } 17 | if (dir === 'U') { 18 | if (x < 5) { 19 | acc.add(`${x + 0.5},${y}`); 20 | x += 1; 21 | } 22 | } 23 | if (dir === 'D') { 24 | if (x > -5) { 25 | acc.add(`${x - 0.5},${y}`); 26 | x -= 1; 27 | } 28 | } 29 | if (dir === 'L') { 30 | if (y > -5) { 31 | acc.add(`${x},${y - 0.5}`); 32 | y -= 1; 33 | } 34 | } 35 | cur = [x, y]; 36 | 37 | return acc; 38 | }, new Set()).size; 39 | 40 | return result; 41 | } 42 | -------------------------------------------------------------------------------- /Programmers/[49994] 방문 길이/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [49994] 방문 길이 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 그래프 탐색 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | if (dir === 'R') { 11 | if (y < 5) { 12 | acc.add(`${x},${y + 0.5}`); 13 | y += 1; 14 | } 15 | } 16 | if (dir === 'U') { 17 | if (x < 5) { 18 | acc.add(`${x + 0.5},${y}`); 19 | x += 1; 20 | } 21 | } 22 | if (dir === 'D') { 23 | if (x > -5) { 24 | acc.add(`${x - 0.5},${y}`); 25 | x -= 1; 26 | } 27 | } 28 | if (dir === 'L') { 29 | if (y > -5) { 30 | acc.add(`${x},${y - 0.5}`); 31 | y -= 1; 32 | } 33 | } 34 | ``` 35 | 36 | - 주어진 방향으로 이동하면서 방문한 선분에 정보를 표시하기 위해서 0.5칸 이동한 정보를 Set에 저장한다. 37 | 38 | ## :black_nib: **Review** 39 | 40 | - 선분의 방문 정보를 표현해야하는데 그걸 어떻게 표현할지가 중요한 문제였다. 41 | -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [62048] 멀쩡한 사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 유클리드 호제법, 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | long gcb = (long)getGcb(w, h); 11 | answer = ((long)w*h) - (gcb * (w/gcb + h/gcb -1)); 12 | ``` 13 | 14 | 사각형은 가로, 세로의 최대공약수 크기로 나눌 수 있다. 15 |
16 | 이렇게 나누어진 사각형에서 사용하지 못하는 영역의 크기는 `가로+세로-1`로 공식을 구할 수 있다.
17 | 18 | ```java 19 | int getGcb(int a, int b){ 20 | int n; 21 | 22 | while(b!=0){ 23 | n = a%b; 24 | a = b; 25 | b = n; 26 | } 27 | 28 | return a; 29 | } 30 | ``` 31 | 32 | 유클리드 호제법으로 두 수의 최대 공약수를 구한다.
33 | 34 | ## :black_nib: **Review** 35 | 36 | - 분명 규칙이 있는데 찾기 어려웠다. 37 | - 사각형의 가로, 세로가 짝수와 홀수일 때로 나누어 생각해 보고 큰 사각형이 작은 사각형으로 나누어 질 수 있다는 것까진 알아갔다. 하지만 최대공약수 개념을 생각하지 못해 답을 확인했다. 38 | - 최대공약수를 구하는 유클리드 호제법을 배웠다. 39 | - BigIngteger class에도 최대공약수를 구하는 함수가 있다. 40 | - 하지만 유클리드 호제법이 이론은 어려울지 몰라도 로직자체는 간단하여 외워야 겠다! 41 | -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/HyeW/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public long solution(int w, int h) { 5 | long answer = 1; 6 | 7 | long gcb = (long)getGcb(w, h); 8 | answer = ((long)w*h) - (gcb * (w/gcb + h/gcb -1)); 9 | 10 | return answer; 11 | } 12 | 13 | // 유클리드 호제 최대공약수 구하기 14 | int getGcb(int a, int b){ 15 | int n; 16 | 17 | while(b!=0){ 18 | n = a%b; 19 | a = b; 20 | b = n; 21 | } 22 | 23 | return a; 24 | } 25 | } -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/asever0318/README.md: -------------------------------------------------------------------------------- 1 | # [62048] 멀쩡한 사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 최대공약수 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | public long solution(long w, long h) { 11 | long answer = 1; 12 | 13 | answer = (w * h) - (w + h - gdc(w, h)); 14 | 15 | return answer; 16 | } 17 | 18 | // 최대공약수 19 | static long gdc(long w, long h){ 20 | long gdc = 0; 21 | 22 | for(long i = 1; i <= w && i <= h; i++){ 23 | if(w % i == 0 && h % i == 0){ 24 | gdc = i; 25 | } 26 | } 27 | return gdc; 28 | } 29 | ``` 30 | 31 | - 겹치는 부분의 개수를 (가로 + 세로 - 최대공약수)로 구할 수 있었다. 32 | - 사용할 수 있는 정사각형의 개수는 전체 - 겹치는 부분의 개수로 구했다. 33 | 34 | ## :black_nib: **Review** 35 | 36 | - 규칙은 찾았는데 이게 최대공약수인 것은 답을 보고 알았다.. 37 | -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/asever0318/Solution_62048.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public long solution(long w, long h) { 5 | long answer = 1; 6 | 7 | // 사용할 수 있는 부분 = 전체 - 겹치는 부분(가로 + 세로 - 최대공약수) 8 | answer = (w * h) - (w + h - gdc(w, h)); 9 | 10 | return answer; 11 | } 12 | 13 | // 최대공약수 14 | static long gdc(long w, long h){ 15 | long gdc = 0; 16 | 17 | for(long i = 1; i <= w && i <= h; i++){ 18 | if(w % i == 0 && h % i == 0){ 19 | gdc = i; 20 | } 21 | } 22 | return gdc; 23 | } 24 | } -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [62048] 멀쩡한 사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | ## :round_pushpin: **Logic** 6 | 7 | ```java 8 | public static long solution(int w, int h) { 9 | long answer = 1; 10 | long gcd = calGcd(w, h); 11 | answer = ((long) w * h) - (((w / gcd) + (h / gcd) - 1) * gcd); 12 | return answer; 13 | } 14 | 15 | public static long calGcd(int w, int h) { 16 | if (h == 0) { 17 | return w; 18 | } 19 | return calGcd(h, w % h); 20 | } 21 | ``` 22 | 23 | - 선이 왼쪽 위 꼭짓점와 오른쪽 아래 꼭짓점을 지나는 가장 작은 직사각형으로 나누어 패턴을 찾는다. 24 | - 위 직사각형의 높이를 h, 길이를 w라고 한다. 25 | - 이 직사각형에서 사용할 수 없는 직사각형의 개수는 w + h - 1이다. 26 | - 유클리드 호제법으로 최대공약수를 구해주었다. 27 | 28 | ## :black_nib: **Review** 29 | 30 | - 입력의 범위가 1억 이하의 자연수라서, 특정 패턴을 찾아야 하는 문제임은 알았다. 31 | - 하지만 찾지 못하여 답을 참고 하였다... 32 | -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public static long solution(int w, int h) { 3 | long answer = 1; 4 | long gcd = calGcd(w, h); 5 | answer = ((long) w * h) - (((w / gcd) + (h / gcd) - 1) * gcd); 6 | return answer; 7 | } 8 | 9 | public static long calGcd(int w, int h) { 10 | if (h == 0) { 11 | return w; 12 | } 13 | return calGcd(h, w % h); 14 | } 15 | } -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [62048] 멀쩡한 사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 수학 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | (long) w * h - (((w / num) + (h / num) - 1) * num); 11 | 12 | ``` 13 | 14 | - 가로와 세로 길이의 최대 공약수 만큼 공통적으로 나타나는 모양의 사각형의 개수를 전체 사각형의 개수에서 빼준다. 15 | 16 | ```java 17 | public int gcd(int a, int b) { 18 | int temp; 19 | while (b > 0) { 20 | temp = a % b; 21 | a = b; 22 | b = temp; 23 | } 24 | return a; 25 | } 26 | ``` 27 | 28 | - 유클리드 호제법을 이용하여 최대 공약수를 구한다. 29 | 30 | ## :black_nib: **Review** 31 | 32 | - 가로, 세로의 최대 길이가 1억 이하의 자연수였기때문에 특정한 공식을 찾아야겠다는 생각을 했다. 33 | - 하지만 아무리 봐도 방법이 떠오르지 않아 결국 답을 보게되었다... 34 | -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/ksg2388/Soultion.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public long solution(int w, int h) { 3 | int temp, num; 4 | if (h > w) { 5 | temp = h; 6 | h = w; 7 | w = temp; 8 | } 9 | 10 | num = gcd(w, h); 11 | return (long) w * h - (((w / num) + (h / num) - 1) * num); 12 | } 13 | 14 | public int gcd(int a, int b) { 15 | int temp; 16 | while (b > 0) { 17 | temp = a % b; 18 | a = b; 19 | b = temp; 20 | } 21 | return a; 22 | } 23 | } -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [62048] 멀쩡한 사각형 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 최대공약수 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static int gcd(int w, int h) { 11 | 12 | int smallNum = (w < h) ? w : h; 13 | 14 | for(int i=smallNum; i>0; i--) { 15 | if(w % i == 0 && h % i == 0) { 16 | return i; 17 | } 18 | } 19 | 20 | return 1; 21 | } 22 | ``` 23 | 24 | - 최대공약수를 구한다. 25 | 26 | ```java 27 | int gcd = gcd(w, h); 28 | long diagonal = w + h - gcd; 29 | return (long)w * h - diagonal; 30 | ``` 31 | 32 | - 전체 넓이 - (대각선에 걸쳐진 사각형의 개수) 가 정답이다 33 | - 대각선에 걸쳐진 사각형의 개수 = (w/gcd + h/gcd -1)*gcd = w + h - gcd 34 | 35 | ## :black_nib: **Review** 36 | 37 | - 수학적 개념이 들어가서 규칙을 찾기가 매우 어려웠다... 38 | - 수학적 규칙을 찾았다면, 그 공식을 최소로 축약해서 코드에 적용하도록 하자. 39 | -------------------------------------------------------------------------------- /Programmers/[62048] 멀쩡한 사각형/yeahLim/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public long solution(int w, int h) { 4 | 5 | int gcd = gcd(w, h); 6 | long diagonal = w + h - gcd; // 대각선에 걸쳐진 사각형의 개수 7 | return (long)w * h - diagonal; 8 | } 9 | 10 | /* 최대 공약수 구하기 */ 11 | static int gcd(int w, int h) { 12 | 13 | int smallNum = (w < h) ? w : h; 14 | 15 | for(int i=smallNum; i>0; i--) { 16 | if(w % i == 0 && h % i == 0) { 17 | return i; 18 | } 19 | } 20 | 21 | return 1; 22 | } 23 | } -------------------------------------------------------------------------------- /Programmers/[67259] 경주로 건설/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [67259] 경주로 건설 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 직선으로 가는 경우 11 | if (i % 2 == cur.dir % 2) { 12 | if (cost[nx][ny][i] > cost[cur.x][cur.y][cur.dir] + 100) { 13 | cost[nx][ny][i] = cost[cur.x][cur.y][cur.dir] + 100; 14 | q.offer(new Current(nx, ny, i)); 15 | 16 | } 17 | } 18 | // 코너로 도는 경우 19 | else { 20 | if (cost[nx][ny][i] > cost[cur.x][cur.y][cur.dir] + 600) { 21 | cost[nx][ny][i] = cost[cur.x][cur.y][cur.dir] + 600; 22 | q.offer(new Current(nx, ny, i)); 23 | 24 | } 25 | } 26 | ``` 27 | 28 | - 상(0), 하(1), 좌(2), 우(3)의 방향 숫자를 지정하였다. 29 | - 방향 숫자를 짝수로 나눴을 때, 같을 경우를 직선으로 가는 경우, 다를 경우 코너로 도는 경우로 나누어서 진행했다. 30 | - cost값이 더 작아질 경우에만 queue에 넣어주었다. 31 | 32 | ## :black_nib: **Review** 33 | 34 | - 처음에 DFS로 풀려고하다가, 코드 작성하면서 BFS로 바꾸어서 풀었다. 35 | - 방향처리 할때, 어느 방향으로 왔는지 처리하는 부분이 중요했다. 36 | - cost의 초기 값을 MAX값으로 주었는데, 이때 start지점의 cost값을 다시 0으로 설적해 주지 않아서 계속 MAX값만 정답이 나왔다. 이 부분 조심해야겠다. 37 | -------------------------------------------------------------------------------- /Programmers/[68646] 풍선 터트리기/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [68646] 풍선 터트리기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // i일때 왼쪽 원소의 최소값 저장 11 | for (int index = 1; index < length - 1; index++) { 12 | if (leftMin > a[index]) { 13 | leftMin = a[index]; 14 | } 15 | lefts[index] = leftMin; 16 | } 17 | ``` 18 | 19 | - 각 풍선을 기준으로 왼쪽에 있는 최소 풍선 번호와 오른쪽에 있는 최소 풍선 번호를 구한다. 20 | 21 | ```java 22 | int answer = 2; 23 | for (int index = 1; index < length - 1; index++) { 24 | // 해당 풍선이 자신을 기준으로 왼쪽에 있는 최소 번호 풍선과, 오른쪽에 있는 최소 번호 풍선보다 크다면, 최후까지 남을 수 있다. 25 | if (a[index] > lefts[index] && a[index] > rights[index]) { 26 | continue; 27 | } 28 | answer++; 29 | } 30 | ``` 31 | 32 | - 현재 풍선이 왼쪽에 있는 최소 풍선 번호보다 크고, 오른쪽에 있는 최소 풍선 보다 크다면 최후까지 남을 수 있는 풍선이다. 33 | 34 | ## :black_nib: **Review** 35 | 36 | - 왼쪽, 오른쪽을 나누어서 최솟값들을 모두 구해놓는 아이디어는 도저히 생각해내지 못할 것 같다. 37 | -------------------------------------------------------------------------------- /Programmers/[68646] 풍선 터트리기/jungu12/Solution.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int solution(int[] a) { 3 | if (a.length == 1) { 4 | return 1; 5 | } 6 | int answer = 2; 7 | int[] leftMin = new int[a.length]; 8 | int[] rightMin = new int[a.length]; 9 | 10 | leftMin[0] = a[0]; 11 | rightMin[a.length - 1] = a[a.length - 1]; 12 | 13 | for (int j = 1; j < a.length - 1; j++) { 14 | leftMin[j] = Math.min(leftMin[j - 1], a[j - 1]); 15 | } 16 | 17 | for (int j = a.length - 2; j > 0; j--) { 18 | rightMin[j] = Math.min(rightMin[j + 1], a[j + 1]); 19 | } 20 | 21 | for (int i = 1; i < a.length - 1; i++) { 22 | if(leftMin[i] < a[i] && rightMin[i] < a[i]) { 23 | continue; 24 | } 25 | answer++; 26 | } 27 | return answer; 28 | } 29 | } -------------------------------------------------------------------------------- /Programmers/[77485] 행렬 테두리 회전하기/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [77485] 행렬 테두리 회전하기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ## :black_nib: **Review** 10 | 11 | - 하라는 대로 하면서 최솟값을 구하면 끝나는 문제. 12 | -------------------------------------------------------------------------------- /Programmers/[77485] 행렬 테두리 회전하기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [77485] 행렬 테두리 회전하기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | let temp = map[x2][y2]; 11 | let list = []; 12 | list.push(temp); 13 | // 반시계로 돌면서 값 전달 14 | // 위 -> 아래 15 | for (let i = x2; i > x1; i--) { 16 | list.push(map[i][y2]); 17 | map[i][y2] = map[i - 1][y2]; 18 | } 19 | // 왼쪽 -> 오른쪽 20 | for (let i = y2; i > y1; i--) { 21 | list.push(map[x1][i]); 22 | map[x1][i] = map[x1][i - 1]; 23 | } 24 | // 아래 -> 위 25 | for (let i = x1; i < x2; i++) { 26 | list.push(map[i][y1]); 27 | map[i][y1] = map[i + 1][y1]; 28 | } 29 | // 오른쪽 -> 왼쪽 30 | for (let i = y1; i < y2 - 1; i++) { 31 | list.push(map[x2][i]); 32 | map[x2][i] = map[x2][i + 1]; 33 | } 34 | ``` 35 | 36 | - 오른쪽 가장 아래 값을 `temp`에 저장 시켜두고 반시계방향으로 돌면서 배열을 회전시킨다. 37 | 38 | ## :black_nib: **Review** 39 | 40 | - 배열 돌리기 문제를 많이 풀다보니 인덱스 계산에 익숙해져 빠르게 풀 수 있었다. ㅎㅎ 41 | -------------------------------------------------------------------------------- /Programmers/[92341] 주차 요금 계산/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [92341] 주차 요금 계산 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | Map 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | // 차 번호별 입차 시간을 저장하는 배열 11 | private final int[] carTimes = new int[10000]; 12 | // 차 번호별 누적 주차 시간을 저장하는 map 13 | private final int[] cumulativeTimes = new int[10000]; 14 | ``` 15 | 16 | - 차 번호별 입차 시간을 저장한다. 17 | - 해당 번호의 출차 기록이 나오면, 누적 주차 시간을 계산해서 누적 주차 시간 저장 배열에 저장한다. 18 | 19 | ## :black_nib: **Review** 20 | 21 | - 문제는 간단하다. 예전에 풀었을 때는 Map을 사용해서 풀었었는데, 이번에는 이를 배열로 바꿔서 풀어보았다. 22 | - 차 번호가 10000개까지 가능해서, 10000개짜리 배열을 2개 만들어서 그런지 탐색 시간으로 인해서 시간이 훨씬 더 많이 사용되었다. 23 | -------------------------------------------------------------------------------- /Programmers/[92341] 주차 요금 계산/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [92341] 주차 요금 계산 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```javascript 10 | records.forEach(v => { 11 | let [time, car, type] = v.split(" "); 12 | const [hour, minute] = time.split(":"); 13 | 14 | // 분으로 바꾸기 15 | time = hour * 60 + Number(minute); 16 | 17 | // 처음 조회되는 차량일 시 18 | if (!cars[car]) { 19 | cars[car] = { time: 0, car }; 20 | } 21 | cars[car].type = type; 22 | 23 | if (type == "OUT") { 24 | cars[car].time += time - cars[car].lastInTime; 25 | return; 26 | } 27 | cars[car].lastInTime = time; 28 | }); 29 | ``` 30 | 31 | - 객체에 차 번호, 마지막으로 입차한 시간, 총 주차장을 이용한 시간을 저장한다. 32 | - 그 정보를 이용하여 각 차별 주차요금을 계산한다. 33 | 34 | ## :black_nib: **Review** 35 | 36 | - 어떤 자료구조를 사용할지 고민하다가 간단하게 객체를 이용하여 풀었다. 37 | - 자바스크립트 내부 메서드가 많아서 잘 사용하면 코드를 간단하게 만들 수 있었다. -------------------------------------------------------------------------------- /Programmers/[92342] 양궁대회/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [92342] 양궁대회 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 중복조합, 완전탐색 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private void lionshoot(int d, int s, int n, int[] info, int[] arrow){ 11 | if(d == n){ 12 | countScore(info, arrow); 13 | return; 14 | } 15 | 16 | for(int i = s; i < 11; i++){ 17 | arrow[i]++; 18 | lionshoot(d+1, i, n, info, arrow); 19 | arrow[i]--; 20 | } 21 | } 22 | ``` 23 | 24 | - 중복 조합을 사용해 라이언이 가진 화살로 낼 수 있는 점수를 다 구했다. 25 | - 화살을 다 쏘는 순간 어피치와의 점수 차이를 구한다. 26 | 27 | 28 | ## :black_nib: **Review** 29 | 30 | - 제한시간이 10초인 것을 보고 완탐 문제이구나라고 생각했는데 완탐으로 풀기 싫어서 고민을 조금해버렸다.. 앞으론 완탐으로 할 수 있으면 그냥 완탐으로 풀자! 31 | - 처음에 단순 조합을 생각했는데 같은 점수도 맞출 수 있으니 중복 조합이었다. 32 | - 그리고 문제를 제대로 안읽어서 라이언의 점수를 리턴하는지 알았다.하지만 점수차를 구해야 했다. 문제 잘 읽자! 33 | - 이거 때문에 조금 헤맸다. -------------------------------------------------------------------------------- /SWEA/[1225] 암호생성기/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [1225] 암호생성기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 큐 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static String generatePwd() { 11 | int minus = 1; 12 | while (true) { 13 | int number = numbers.poll(); 14 | number -= minus++; 15 | 16 | if (minus == 6) { 17 | minus = 1; 18 | } 19 | 20 | if (number <= 0) { 21 | number = 0; 22 | numbers.add(number); 23 | break; 24 | } 25 | 26 | numbers.add(number); 27 | } 28 | 29 | return queueToString(); 30 | } 31 | ``` 32 | 33 | - 큐를 사용해 숫자에 대한 감소 연산을 수행하고 다시 큐에 삽입한다. 34 | - 숫자에 대한 연산 결과가 0 이하인 경우, 큐에 넣고 반복을 종료한다. 35 | 36 | ## :black_nib: **Review** 37 | - 1단계씩 직접 연산을 수행하지 않고 해결할 방법이 없을까하다가, 방법을 찾지 못했다. 38 | - 직접 연산을 수행하는 방식을 구현하기 위해서는 큐가 가장 적절한 자료구조인 것 같아 사용했다. -------------------------------------------------------------------------------- /SWEA/[1225] 암호생성기/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [1225] 암호 생성기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 |     static void pro() { 11 |         int now; 12 |         for(int i = 0 ; ; i++) { 13 |             if(pw[(i+7)%8] == 0) { 14 |                 now = i; 15 |                 break; 16 |             } 17 |             pw[i % 8] -= (i%5+1); 18 |             if(pw[i % 8] < 0) 19 |                 pw[i % 8] = 0; 20 |         } 21 |         System.out.print("#" + (T++)+ " "); 22 |         for(int i = 0 ; i < 8 ; i++) { 23 |             System.out.print(pw[(i+now)%8] + " "); 24 |         }System.out.println(); 25 |     } 26 | ``` 27 | - 배열에 저장하고 현재 index를 지칭하는 now 변수로 현재 위치에 접근했다. 28 | 29 | 30 | ## :black_nib: **Review** 31 | - 보다 더 적절한 자료구조를 활용하지 않고 그냥 배열로 해결한 것 같다. 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /SWEA/[1225] 암호생성기/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 백트레킹 4 | 5 | ## 중요 구현 로직 및 설명 6 | 7 | image 8 | 마지막까지 모두 검사한 경우 포인트가 현재 저장되어있는 최대 포인트보다 많은 경우 그 값으로 갱신해준다. 9 | 현재 음식을 넣는 경우와 넣지 않는 경우 두 가지 경우를 모두 검사하며 도중 제한칼로리보다 현재 칼로리가 더 높아지는 경우는 탐색을 중지한다. 10 | 11 | ## 풀이 후기 12 | 13 | 더 쉽게 풀 수 있는 방법이 있을 것 같은데 떠오르지 않는다... 14 | -------------------------------------------------------------------------------- /SWEA/[1225] 암호생성기/ksg2388/swea1225.java: -------------------------------------------------------------------------------- 1 | package practice.sw; 2 | 3 | import java.util.*; 4 | import java.io.*; 5 | 6 | class sw1225 { 7 | 8 | public static void main(String args[]) throws IOException { 9 | 10 | BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 11 | 12 | 13 | for (int tc = 1; tc <= 10; tc++) { 14 | int n = Integer.parseInt(br.readLine()); 15 | List codes = new ArrayList<>(); 16 | StringTokenizer st = new StringTokenizer(br.readLine()); 17 | boolean isComplete = true; 18 | 19 | for (int i = 0; i < 8; i++) 20 | codes.add(Integer.parseInt(st.nextToken())); 21 | 22 | while(isComplete) { 23 | for(int i = 1; i <= 5; i++) { 24 | int temp = codes.remove(0) - i; 25 | if (temp <= 0) { 26 | codes.add(0); 27 | isComplete = false; 28 | break; 29 | } 30 | codes.add(temp); 31 | } 32 | } 33 | 34 | 35 | System.out.print("#" + n + " "); 36 | for (int code: codes) 37 | System.out.print(code + " "); 38 | System.out.println(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /SWEA/[1225] 암호생성기/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [1225] 암호생성기 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | - 0이 도출될때까지, 각 원소에 num만큼 빼줌 9 | - 데이터 타입을 배열을 그대로 사용하고, 직접 순회하면서 값을 변경해줌 10 | - 실제로 데이터 값을 삭제하고 다시 추가하면 메모리 및 시간이 많이 소모되기 때문 11 | ```java 12 | for(int i=0; i<8; i++) { 13 | 14 | arr[i] -= num; 15 | 16 | if(arr[i] <= 0) { 17 | arr[i] = 0; 18 | idx = i+1; 19 | break; 20 | } 21 | 22 | num++; 23 | 24 | if(num == 6) 25 | num = 1; 26 | 27 | if(i == 7) 28 | i = -1; 29 | } 30 | ``` 31 | ## :black_nib: **Review** 32 | -------------------------------------------------------------------------------- /SWEA/[1234] 비밀번호/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [1234] 비밀번호 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 구현 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 주어진 값을 LinkedList에 저장해서 모든 수를 읽으며 중복되는 숫자를 삭제해주었다.
10 | 11 | ```java 12 | static int removeNum(int left, int right) { 13 | while ((left >= 0) && (right < number.size())) { 14 | 15 | if (number.get(left) != number.get(right)) { 16 | break; 17 | } 18 | 19 | number.remove(left); 20 | number.remove(left); 21 | 22 | left--; 23 | right--; 24 | } 25 | return left+1; 26 | } 27 | ``` 28 | 29 | 비교할 값의 index 2개를 받아서 두 수가 같다면 계속 삭제하는 방법으로 문제를 해결했다.
30 | 여기서 left에 있는 값을 삭제하면 삭제한 값의 오른쪽 값들의 index가 1씩 작아지니 left index를 두번 삭제했다.
31 | 32 | ## :black_nib: **Review** 33 | - 주어진 수열에서 특정 값을 삭제하는 문제라서 배열의 삭제가 쉬운 연결 리스트를 이용해서 문제를 해결했다. 34 | -------------------------------------------------------------------------------- /SWEA/[1234] 비밀번호/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [1234] 비밀번호 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 스택 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static String removePairs(String word) { 11 | Stack words = new Stack<>(); 12 | for (int index = 0; index < word.length(); index++) { 13 | char current = word.charAt(index); 14 | 15 | if (!words.empty() && words.peek() == current) { 16 | words.pop(); 17 | continue; 18 | } 19 | words.push(current); 20 | } 21 | return stackToString(words); 22 | } 23 | ``` 24 | 25 | - 스택을 이용해 쌍을 이루는 문자를 제거한다. 26 | 27 | ## :black_nib: **Review** 28 | - 이전에도 비슷한 문제를 많이 풀어봤어서 스택을 사용하는 문제임을 바로 알 수 있었다. -------------------------------------------------------------------------------- /SWEA/[1234] 비밀번호/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [1234] 비밀번호 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 6 | ## :round_pushpin: **Logic** 7 | 8 | ```java 9 | static void check(int idx) { 10 | if (idx >= pw.size() - 1) { 11 | return; 12 | } 13 | if (pw.get(idx) == pw.get(idx + 1)) { 14 | for (int i = 0; i < 2; i++) { 15 | pw.remove(idx); 16 | } 17 | check((idx - 1 < 0) ? 0 : idx-1); 18 | } else { 19 | check(idx + 1); 20 | } 21 | } 22 | ``` 23 | - pw라는 Arraylist에 input을 입력 받은 후, pw의 0번째부터 조건을 만족하는 짝을 찾아 remove 해준다. 24 | - 조건을 만족하는 짝을 찾는다면 idx - 1 해주고 다시 짝을 찾는다. 25 | 26 | 27 | ## :black_nib: **Review** 28 | - 조건을 찾아 idx - 1을 해줄 경우, 0보다 작아 질 수 있다는 것을 뒤늦게 생각하였다. 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /SWEA/[1234] 비밀번호/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [1234] 비밀번호 2 | 3 | ## :pushpin: **Algorithm** 4 | stack 5 | 6 | ## :round_pushpin: **Logic** 7 | ``` java 8 | for (int i = 0; i < n; i++) { 9 | if (stack.isEmpty()) { 10 | stack.add(code.charAt(i)); 11 | continue; 12 | } 13 | if (stack.peek() == code.charAt(i)) { 14 | stack.pop(); 15 | continue; 16 | } 17 | stack.add(code.charAt(i)); 18 | } 19 | ``` 20 | - stack이 비어있는 경우 바로 문자를 넣는다. 21 | - stack이 존재하는 경우 stack의 가장 위에있는 값과 새로 들어오는 값을 비교해 같은 경우 stack에 그 값을 넣지 않고 기존 stack의 가장 위에 있는 값을 삭제한다. 22 | 23 | ## :black_nib: **Review** 24 | - 생각보다 어렵지 않은 문제라 쉽게 풀 수 있었다. -------------------------------------------------------------------------------- /SWEA/[1234] 비밀번호/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [1234] 비밀번호 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 스택 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | int i = 0; 11 | while (!seq.isEmpty()) { 12 | 13 | if (seq.get(i) == seq.get(i + 1)) { 14 | seq.remove(i); 15 | seq.remove(i); 16 | i = (i == 0) ? i : --i; // 인덱스가 0이 아니면 -1 17 | } else { 18 | i++; 19 | } 20 | 21 | if (i == seq.size() - 1) { 22 | break; 23 | } 24 | 25 | } 26 | ``` 27 | 28 | - list의 index를 이용해 i와 i+1가 같다면 두 숫자를 제거해주고, 이후 index의 값을 -1로 설정 후 다시 같은 숫자가 있는 지 탐색한다. 29 | - 만약 두 숫자가 같지 않다면 인데스 값을 i+1 해주고 전부다 돌면 종료한다. 30 | 31 | ## :black_nib: **Review** 32 | - 단순 구현으로 쉽게 풀었는데, stack으로도 풀어봐야겠다. 33 | -------------------------------------------------------------------------------- /SWEA/[3752] 가능한 시험 점수/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [3752] 가능한 시험 점수 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 집합 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void makeScore() { 11 | for (int score : scores) { 12 | Set tempScores = new HashSet<>(); 13 | for (int setScore : scoreSet) { 14 | tempScores.add(setScore + score); 15 | } 16 | scoreSet.addAll(tempScores); 17 | } 18 | } 19 | ``` 20 | 21 | - 점수를 하나씩 이미 구한 점수 SET의 점수에 더해 다시 SET에 추가한다. 22 | - 0, A -> 0, A, B, A + B -> 0, A, B, A + B, C, A + C, B + C, A + B + C 23 | 24 | ## :black_nib: **Review** 25 | - 처음에는 조합을 사용해 모든 경우를 구하고, 이를 Set에 넣는 방식으로 하려 했다. 26 | - 시간 초과가 났고, 조합은 $O(2^N)$의 복잡도를 가져 주어진 조건에서는 무조건 시간 초과가 날 수밖에 없었다. 27 | - 하지만 모든 경우를 직접 구해보지 않고는 문제를 해결할 수 없어보여서 고민 끝에 접근법을 좀 찾아봤다. 28 | - 수학적으로 접근해야 식이 보이는 느낌이었다.. -------------------------------------------------------------------------------- /SWEA/[3752] 가능한 시험 점수/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [3752] 가능한 시험 점수 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void calScore() { 11 | for (int i = 0; i < N; i++) { 12 | Set tmp = new HashSet<>(); 13 | tmp.addAll(possibleScore); 14 | for (int s : tmp) { 15 | possibleScore.add(s + score[i]); 16 | } 17 | } 18 | } 19 | ``` 20 | - 점수를 Set에 관리하여 중복 점수를 처리해주었다. 21 | - 만들어진 점수들에 새로운 문제의 배점을 더하여 새로운 점수를 만들었다. 22 | 23 | 24 | ## :black_nib: **Review** 25 | - 백 트래킹으로 가능한 모든 점수들을 계산하려 하였으나, 시간 초과로 풀지 못하였다. 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /SWEA/[3752] 가능한 시험 점수/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 구현 4 | 5 | ## 중요 구현 로직 및 설명 6 | 1. Set에 0을 넣어 초기화해둔다. 7 | 2. 새로운 값이 들어올때마다 Set에 있는 값들에 그 값을 더한 값을 다시 Set에 추가해준다. 8 | 9 | ```java 10 | int n = Integer.parseInt(br.readLine()); 11 | st = new StringTokenizer(br.readLine()); 12 | Set scores = new HashSet<>(Arrays.asList(0)); 13 | 14 | for (int i = 0; i < n; i++) { 15 | int num = Integer.parseInt(st.nextToken()); 16 | List temp = new ArrayList<>(scores); 17 | for (int j = 0; j < temp.size(); j++) { 18 | scores.add(temp.get(j) + num); 19 | } 20 | } 21 | ``` 22 | Set에 있는 값을 리스트로 만든 후 그 값들에 새로 들어온 값들을 더해 Set에 추가하면서 길이만큼 반복해준다. 23 | 24 | ## 풀이 후기 25 | 26 | 어떤 식으로 푸는 것이 효율적인지 많이 생각해 볼 수 있는 문제였다. 27 | -------------------------------------------------------------------------------- /SWEA/[3752] 가능한 시험 점수/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [3752] 가능한 시험 점수 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 부분 집합, DP 6 | 7 | ## :round_pushpin: **Logic** 8 | ```java 9 | for (int i = 0; i < n; i++) { 10 | /* 입력된 점수를 매개변수로 넘겨 점수의 경우의 수 구하기 */ 11 | getScoreCases(Integer.parseInt(st.nextToken())); 12 | } 13 | ``` 14 | - for문으로 입력된 점수의 값을 하나씩 getScoreCases로 넘겨준다. 15 | 16 | ```java 17 | static void getScoreCases(int score) { 18 | Set tmp = new HashSet<>(); 19 | tmp.addAll(set); 20 | for(int s : tmp) { 21 | set.add(s + score); 22 | } 23 | } 24 | ``` 25 | 26 | - tmp 집합에 set 집합을 복사하고, 매개변수로 받은 score값과 tmp 집합을 순회한 값을 더해서 set집합에 넣어준다. 27 | - 0, 0 + a / 0, a, 0+b, a+b / 0, a, b, 0+c, a+c, b+c, a+b+c ... 28 | - 그 다음 입력값을 받으면, 새로 추가된 set집합에 위를 반복한다. 29 | 30 | ## :black_nib: **Review** 31 | - return값이 없는데 메소드 이름이 get으로 시작되니까 뭔가 아닌 것 같다. 앞으로 set으로 바꿔줘야겠다. 32 | -------------------------------------------------------------------------------- /SWEA/[5215] 햄버거 다이어트/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [5215] 햄버거 다이어트 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 브루트포스 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void findMaxScore(int index, int score, int calorie) { 11 | if (calorie > L) { 12 | return; 13 | } 14 | 15 | if (index == N) { 16 | maxScore = Math.max(maxScore, score); 17 | return; 18 | } 19 | 20 | findMaxScore(index + 1, score + scores[index], calorie + calories[index]); 21 | findMaxScore(index + 1, score, calorie); 22 | } 23 | ``` 24 | 25 | - index에 해당하는 음식을 넣거나, 넣지 않는 모든 경우에 대해 계산한다. 26 | 27 | ## :black_nib: **Review** 28 | - 강의실 배정 문제와 비슷하게 우선순위 큐를 사용하는 방식으로 접근했다가, 반례를 찾지 못해 모든 경우를 탐색할 수 있는 방식으로 변경했다. 29 | - 더 빠르게 풀 수 있도록 구현 시간을 단축시켜야겠다. -------------------------------------------------------------------------------- /SWEA/[5215] 햄버거 다이어트/jungu12/README.md: -------------------------------------------------------------------------------- 1 | # [5215] 햄버거 다이어트 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 브루트포스 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | static void add(int idx, int taste, int sum) { 11 | if(sum > calLimit) 12 | return; 13 | if(taste > best) 14 | best = taste; 15 | if(idx == numLimit) 16 | return; 17 | add(idx+1, taste+ingredient[idx][0], sum+ingredient[idx][1]); 18 | add(idx+1, taste, sum); 19 | } 20 | ``` 21 | - 이차원 배열에 재료별 맛과 칼로리를 저장하였다. 22 | - 배열을 돌면서 하나씩 추가 하거나 추가 하지 않고 다음 재료 선택으로 넘어갔다. 23 | 24 | ## :black_nib: **Review** 25 | - 큰 어려움 없이 해결하였다. 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /SWEA/[5215] 햄버거 다이어트/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | ## 사용한 알고리즘 2 | 3 | 딱히 없음 4 | 5 | ## 중요 구현 로직 및 설명 6 | 7 | image 8 | 암호가 만들어지지 않은 경우 계속해서 반복을 하며 규칙에 맞게 반복문을 돌다가 맨 마지막 수가 0이거나 0보다 작아지는 경우 0을 넣고 반복문을 종료한다. 9 | 10 | ## 풀이 후기 11 | 12 | 생각보다 쉬웠다. 13 | -------------------------------------------------------------------------------- /SWEA/[5215] 햄버거 다이어트/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [5215] 햄버거 다이어트 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | 브루트포스 6 | 7 | ## :round_pushpin: **Logic** 8 | - 햄버거 재료 하나마다 추가한 경우와 추가하지 않은 경우를 모두 구함 9 | - 백트래킹 이용 10 | ```java 11 | static void backtrck(int idx, int scoreSum, int calSum) { 12 | 13 | if (calSum > cal) 14 | return; 15 | 16 | if(idx == n) { 17 | if(maxScore < scoreSum) 18 | maxScore = scoreSum; 19 | return; 20 | } 21 | 22 | // 추가했을 경우 23 | backtrck(idx+1, scoreSum+arr[idx][0], calSum+arr[idx][1]); 24 | // 추가하지 않았을 경우 25 | backtrck(idx+1, scoreSum, calSum); 26 | } 27 | ``` 28 | ## :black_nib: **Review** 29 | - dfs 말고 백트래킹을 이용해 쉽게 구할 수 있음. 30 | -------------------------------------------------------------------------------- /SWEA/[7465] 창용 마을 무리의 개수/HyeW/README.md: -------------------------------------------------------------------------------- 1 | # [7465] 창용 마을 무리의 개수 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | BFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 사람 간의 관계를 양방향 매핑으로 List로 만든다.
10 | 그리고 모든 사람을 확인하며 무리가 있는지 검사한다.
11 | ```java 12 | 13 | static void checkGroup(int start) { 14 | Queue q = new LinkedList<>(); 15 | q.add(start); 16 | connected[start] = true; 17 | 18 | while(!q.isEmpty()) { 19 | int cur = q.poll(); 20 | 21 | for(int nxt : village.get(cur)) { 22 | 23 | if(connected[nxt]) { 24 | continue; 25 | } 26 | 27 | q.add(nxt); 28 | connected[nxt] = true; 29 | 30 | } 31 | } 32 | } 33 | 34 | ``` 35 | 큐에서 하나의 값을 꺼내 그 값과 연결된 사람들을 큐에 넣는다. 이를 반복하는 BFS알고리즘을 사용해 몇 개의 무리가 있는지 구했다.
36 | 37 | 38 | ## :black_nib: **Review** 39 | - 양방향 연결리스트를 만들어서 연결된 노드를 찾는 문제들을 많이 풀어보아 쉽게 해결할 수 있었다. -------------------------------------------------------------------------------- /SWEA/[7465] 창용 마을 무리의 개수/SUbbb/README.md: -------------------------------------------------------------------------------- 1 | # [7465] 창용 마을 무리의 개수 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | DFS 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | ```java 10 | private static void connectFriends(int person) { 11 | isVisited[person] = true; 12 | for (int friend : friends.get(person)) { 13 | if (isVisited[friend]) { 14 | continue; 15 | } 16 | connectFriends(friend); 17 | } 18 | } 19 | ``` 20 | 21 | - 방문하지 않은 정점(사람)에 대해 방문할 수 있는 만큼 방문하고 방문처리를 수행한다. 22 | 23 | ## :black_nib: **Review** 24 | - 연결성을 확인하는 기본적인 문제로, DFS나 Union-Find 알고리즘을 사용해 해결할 수 있는 문제였다. 25 | - 둘 중 어떤 알고리즘이 더 빠를지에 대해서는 문제의 조건에 따라 다른 것 같았다. 26 | - 이미 그래프 정보가 고정되어 있는 경우는 DFS, 동적으로 변할 수 있는 경우는 Union-Find가 조금 더 빠른 것 같다. -------------------------------------------------------------------------------- /SWEA/[7465] 창용 마을 무리의 개수/ksg2388/README.md: -------------------------------------------------------------------------------- 1 | # [7465] 창용 마을 무리의 개수 2 | 3 | ## :pushpin: **Algorithm** 4 | DFS 5 | 6 | ## :round_pushpin: **Logic** 7 | ``` java 8 | for (int i = 0; i < n; i++) { 9 | if (!check[i]) { 10 | checkFriends(i, n); 11 | count++; 12 | } 13 | } 14 | 15 | for (int i = 0; i < n; i++) { 16 | if (!check[i]) { 17 | count++; 18 | } 19 | } 20 | ``` 21 | - 방문하지 않은 경우에 checkFiends 메소드를 이용해 서로 친분이 있는 모든 사람들을 방문처리한다. 22 | - 마지막으로 방문이 되지 않은 사람들의 숫자만큼 count를 증가시킨다. 23 | 24 | ## :black_nib: **Review** 25 | - 푸는 방법에 여러가지 방법들이 있는데 어느 방법이 가장 효율이 좋은지 궁금해졌다. -------------------------------------------------------------------------------- /SWEA/[7465] 창용 마을 무리의 개수/yeahLim/README.md: -------------------------------------------------------------------------------- 1 | # [7465] 창용 마을 무리의 개수 2 | 3 | ## :pushpin: **Algorithm** 4 | 5 | Union-find 6 | 7 | ## :round_pushpin: **Logic** 8 | 9 | 10 | ```java 11 | map = new int[n + 1]; 12 | for (int i = 1; i < n + 1; i++) { 13 | map[i] = i; 14 | } 15 | ``` 16 | - map에 각 숫자에 숫자값을 루트값으로 대입한다. 17 | ```java 18 | /* 다른 무리를 한 무리로 합치기 */ 19 | static void union(int num1, int num2) { 20 | int root1 = searchRoot(num1); 21 | int root2 = searchRoot(num2); 22 | if(root1 != root2) { 23 | map[root2] = root1; 24 | count--; 25 | } 26 | } 27 | 28 | /* 루트값 찾기 */ 29 | static int searchRoot(int num) { 30 | if(map[num] == num) { 31 | return num; 32 | } 33 | return map[num] = searchRoot(map[num]); 34 | } 35 | ``` 36 | - 무리의 개수를 숫자의 개수로 설정한다. 37 | - 루트값이 똑같다면 두 숫자의 무리를 다른 무리로 합치고, 무리의 개수를 -1해준다. 38 | 39 | ## :black_nib: **Review** 40 | - 루트값을 똑같이 대입해주는 방법을 이용해서 푸니까 재밌었다. 41 | -------------------------------------------------------------------------------- /leetcode/check-if-n-and-its-double-exist/java/README.md: -------------------------------------------------------------------------------- 1 | # Check If N And Its Double Exist 2 | 3 | [문제 출처](https://leetcode.com/problems/check-if-n-and-its-double-exist) 4 | 5 | ## 성능 6 | 7 | - Time: 2ms 8 | - Memory: 43MB -------------------------------------------------------------------------------- /leetcode/check-if-n-and-its-double-exist/java/check-if-n-and-its-double-exist.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Solution { 4 | public boolean checkIfExist(int[] arr) { 5 | Set numSet = new HashSet<>(); 6 | 7 | for (int index = 0; index < arr.length; index++) { 8 | int current = arr[index]; 9 | 10 | if (numSet.contains(current)) { 11 | return true; 12 | } 13 | 14 | if (current % 2 == 0) { 15 | numSet.add(current / 2); 16 | } 17 | numSet.add(current * 2); 18 | } 19 | 20 | return false; 21 | } 22 | } -------------------------------------------------------------------------------- /programmers/[42628] 이중우선순위큐/java/README.md: -------------------------------------------------------------------------------- 1 | # [42628] 이중우선순위큐 2 | 3 | [문제 출처](https://school.programmers.co.kr/learn/courses/30/lessons/42628) 4 | 5 | ## 성능 6 | 7 | - Time: 274.05ms 8 | - Memory: 192MB --------------------------------------------------------------------------------