항해99 리부트 알고리즘 1주차의 첫 알고리즘 코테를 진행하였다. 4개중 2개를 풀고 이를 복기해본다.
오늘 진행된 강의에서 학습한 내용은 무엇인가요?
[백준] 스위치켜고끄기 - 1244
https://www.acmicpc.net/problem/1244
스위치 배열 상태 변경 프로그램의 핵심 로직을 분석합니다. 이 로직은 학생들의 명령에 따라 스위치의 상태를 변경하는 기능을 수행합니다.
1. 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.StringTokenizer;
public class Main {
static String solution(BufferedReader br) throws IOException{
StringTokenizer st = new StringTokenizer(br.readLine());
// 스위치 배열 개수
int switchCount = Integer.parseInt(st.nextToken());
// 스위치 배열
String[] switchStatusStrArr = br.readLine().toString().split(" ");
int[] switchStatusIntArray = new int[switchCount];
for(int i = 0; i < switchCount; i++){
switchStatusIntArray[i] = Integer.parseInt(switchStatusStrArr[i]);
}
// 학생수
int studentNum = Integer.parseInt(br.readLine());
for(int i = 0; i < studentNum; i++){
StringTokenizer tmpSt = new StringTokenizer(br.readLine());
int gender = Integer.parseInt(tmpSt.nextToken());
int switchNum = Integer.parseInt(tmpSt.nextToken());
// 남성인 경우
if(gender == 1){
for(int j = switchNum-1; j < switchCount; j++){
int tmpSwitchNum = j+1;
if((tmpSwitchNum % switchNum) == 0){ // 배수인 경우 스위치를 변경함
switchStatusIntArray[j] = switchStatusIntArray[j] != 1 ? 1: 0;
}
}
// 여성인 경우
}else{
int selfPointer = switchNum-1;
int leftPointer = selfPointer-1;
int rightPointer = selfPointer+1;
int conditionToChange = switchStatusIntArray[selfPointer] != 1 ? 1: 0;
// 맨 앞에 있는 경우
if(selfPointer+1 == 1){
switchStatusIntArray[selfPointer] = conditionToChange;
continue;
// 맨 뒤에 있는 경우
}else if(selfPointer+1 == switchCount){
switchStatusIntArray[selfPointer] = conditionToChange;
continue;
// 중앙에 있는 경우
}else{
while(rightPointer < switchCount && 0 <= leftPointer && leftPointer < rightPointer){
// 좌우가 동일하지 않다면
if (switchStatusIntArray[leftPointer] != switchStatusIntArray[rightPointer]){
continue;
// 좌우가 동일하다면, 좌우를 바꿔준다.
}else{
switchStatusIntArray[leftPointer] = (switchStatusIntArray[leftPointer] != 1) ? 1: 0;
switchStatusIntArray[rightPointer] = (switchStatusIntArray[rightPointer] != 1) ? 1: 0;
}
leftPointer--;
rightPointer++;
}
switchStatusIntArray[selfPointer] = conditionToChange;
}
}
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < switchCount; i++){
sb.append(String.valueOf(switchStatusIntArray[i]).concat(" "));
}
return sb.toString();
}
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String answer = solution(br);
System.out.println(answer);
br.close();
}
}
2. 입력 처리
2.1 스위치 개수와 상태 처리
StringTokenizer st = new StringTokenizer(br.readLine());
int switchCount = Integer.parseInt(st.nextToken());
String[] switchStatusStrArr = br.readLine().split(" ");
int[] switchStatusIntArray = new int[switchCount];
for (int i = 0; i < switchCount; i++) {
switchStatusIntArray[i] = Integer.parseInt(switchStatusStrArr[i]);
}
- 첫 번째 줄에서 스위치 개수를 읽고, 두 번째 줄에서 스위치 상태를 정수 배열로 변환합니다.
2.2 학생 수와 명령 처리
int studentNum = Integer.parseInt(br.readLine());
for (int i = 0; i < studentNum; i++) {
StringTokenizer tmpSt = new StringTokenizer(br.readLine());
int gender = Integer.parseInt(tmpSt.nextToken());
int switchNum = Integer.parseInt(tmpSt.nextToken());
- 세 번째 줄에서 학생 수를 읽고, 이후 각 학생의 명령을 처리합니다.
3. 학생 명령 처리
3.1 남학생 명령 처리
if (gender == 1) {
for (int j = switchNum - 1; j < switchCount; j++) {
if ((j + 1) % switchNum == 0) {
switchStatusIntArray[j] = switchStatusIntArray[j] != 1 ? 1 : 0;
}
}
}
- 남학생은 스위치 번호의 배수 위치에 있는 스위치 상태를 반전시킵니다.
3.2 여학생 명령 처리
else {
int selfPointer = switchNum - 1;
int leftPointer = selfPointer - 1;
int rightPointer = selfPointer + 1;
int conditionToChange = switchStatusIntArray[selfPointer] != 1 ? 1 : 0;
switchStatusIntArray[selfPointer] = conditionToChange;
while (rightPointer < switchCount && leftPointer >= 0 && switchStatusIntArray[leftPointer] == switchStatusIntArray[rightPointer]) {
switchStatusIntArray[leftPointer] = switchStatusIntArray[leftPointer] != 1 ? 1 : 0;
switchStatusIntArray[rightPointer] = switchStatusIntArray[rightPointer] != 1 ? 1 : 0;
leftPointer--;
rightPointer++;
}
}
- 여학생은 스위치 번호를 중심으로 좌우 대칭인 스위치 상태를 확인하고, 동일하면 상태를 반전시킵니다.
4. 결과 생성
StringBuilder sb = new StringBuilder();
for (int i = 0; i < switchCount; i++) {
sb.append(switchStatusIntArray[i]).append(" ");
}
return sb.toString().trim();
- 변경된 스위치 상태 배열을
StringBuilder
를 사용하여 문자열로 조합하고, 최종 결과를 반환합니다.
5. 결론
본 프로그램은 학생들의 명령에 따라 스위치 상태를 효과적으로 변경합니다. 남학생과 여학생의 명령 방식에 따른 처리 로직이 각각 구현되어 있으며, 다양한 입력 상황에 대한 처리가 가능합니다.
5.1 향후 개선 사항
- 입력 검증 로직 추가: 유효하지 않은 입력에 대해 예외 처리를 추가할 수 있습니다.
- 코드 최적화: 반복문 및 조건문을 최적화하여 성능을 개선할 수 있습니다.
- 테스트 케이스 추가: 다양한 경계 조건 및 예외 상황에 대한 테스트 케이스를 추가하여 코드의 견고성을 높일 수 있습니다.
[백준]IPv6 - 3107
https://www.acmicpc.net/problem/3107
코드
package IPv6;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
public class Main3 {
public static void runtTestCases() throws IOException {
BufferedReader br = new BufferedReader(new StringReader(input1()));
String[] testCases = new String[]{
input1(),
input2(),
input3(),
input4(),
input5(),
input6(),
input7(),
input8(),
input9(),
input10(),
input11(),
// input12(),
input13(),
// input14(),
};
for (String testCase : testCases) {
String answer = expandIPv6(testCase);
System.out.println("IPv6 address: " + testCase);
System.out.println("Expanded IPv6 address: " + answer);
System.out.println();
}
}
public static void main(String[] args) throws IOException {
// BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// String ipv6Address = br.readLine().trim();
// System.out.println(expandIPv6(ipv6Address));
runtTestCases();
// BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
}
public static String expandIPv6(String ipv6Address) {
// "::"으로 분할, -1은 빈 문자열도 포함하여 분할
String[] parts = ipv6Address.split("::", -1);
String[] leftPart = parts[0].split(":");
// '::' 기준으로 parts 문자열 배열 오른쪽의 길이가 2인 것은 뭔가 있다는 것 그리고 parts[1](parts 문자열 배열 오른쪽)이 들어 있다라는 의미.
// 만약 들어 있지 않다면, rightPart는 깡통으로써 `오른쪽 부분을 fullAddress에 채우기` loop를 수행하지 않는다.
String[] rightPart = (parts.length == 2 && !parts[1].isEmpty())
? parts[1].split(":") :
new String[0];
// 확장된 IPv6 주소를 담을 배열 생성
String[] fullAddress = new String[8];
int leftPartIndex = 0;
// 왼쪽 부분을 fullAddress에 채우기
for (int i = 0; i < leftPart.length; i++) {
fullAddress[leftPartIndex] = leftPart[i];
leftPartIndex++;
}
// 오른쪽 부분을 fullAddress에 채우기
int rightPartIndex = 7;
for (int i = rightPart.length - 1; i >= 0; i--) {
fullAddress[rightPartIndex] = rightPart[i];
rightPartIndex--;
}
// 빈 부분을 "0000"으로 채우기
// 빈 부분 0으로 채우기
for (int i = 0; i < 8; i++) {
if (fullAddress[i] == null || fullAddress[i].isEmpty()) {
fullAddress[i] = "0000";
} else {
fullAddress[i] = String.format("%4s", fullAddress[i]).replace(' ', '0');
}
}
// 결과 조합
return String.join(":", fullAddress);
}
// 출력 : 0025:0009:1985:00aa:0091:4846:0374:00bb
static String input1(){
return "25:09:1985:aa:091:4846:374:bb";
}
// output: 0000:0000:0000:0000:0000:0000:0000:0001
static String input2(){
return "::1";
}
// output: 0000:0000:0001:0002:0003:0004:0005:0006
static String input3() {
return "::1:2:3:4:5:6";
}
// 출력 : 2001:db8:85a3:0000:0000:8a2e:0370:7334
static String input4() {
return "2001:db8:85a3::8a2e:370:7334";
}
// 출력 : fe80:0000:0000:0000:0202:b3ff:fe1e:8329
static String input5() {
return "fe80::202:b3ff:fe1e:8329";
}
// 출력 : 2001:0db8:0000:0000:0000:0000:0000:0001
static String input6() {
return "2001:db8::1";
}
// 출력 : 0000:0000:0000:0000:0000:0000:0000:0001
static String input7() {
return "::1";
}
// 출력 : 2001:0db8:0000:0042:0000:8a2e:0370:7334
static String input8() {
return "2001:db8:0:42::8a2e:370:7334";
}
// 출력 : 0000:0000:0000:0000:0000:0000:0000:0000
static String input9() {
return "::";
}
// 출력 : fe80:0000:0000:0000:0000:0000:0000:0001
static String input10() {
return "fe80::1";
}
// 출력 : ff02:0000:0000:0000:0000:0000:0000:0001
static String input11() {
return "ff02::1";
}
// 출력 : 0000:0000:0000:0000:0000:ffff:c0a8:0101
// static String input12() {
// return "::ffff:192.168.1.1";
// }
// 출력 : 2001:0db8:0000:0000:0000:0000:0000:0000
static String input13() {
return "2001:db8::";
}
}
IPv6 주소를 완전한 8개의 섹션으로 확장하는 프로그램의 핵심 로직을 분석합니다. 이 로직은 축약된 형태의 IPv6 주소를 입력받아 모든 섹션이 4자리로 확장된 IPv6 주소를 생성합니다.
2. 입력 처리 및 확장 로직
2.1 입력 처리
public static void runtTestCases() throws IOException {
BufferedReader br = new BufferedReader(new StringReader(input1()));
String[] testCases = new String[]{
input1(), input2(), input3(), input4(), input5(),
input6(), input7(), input8(), input9(), input10(),
input11(), input13()
};
for (String testCase : testCases) {
String answer = expandIPv6(testCase);
System.out.println("IPv6 address: " + testCase);
System.out.println("Expanded IPv6 address: " + answer);
System.out.println();
}
}
- 여러 IPv6 주소에 대해 확장 로직을 테스트하기 위해 테스트 케이스 배열을 정의하고, 각 테스트 케이스에 대해 확장된 IPv6 주소를 출력합니다.
2.2 IPv6 주소 확장 로직
public static String expandIPv6(String ipv6Address) {
String[] parts = ipv6Address.split("::", -1);
String[] leftPart = parts[0].split(":");
String[] rightPart = (parts.length == 2 && !parts[1].isEmpty()) ? parts[1].split(":") : new String[0];
String[] fullAddress = new String[8];
int leftPartIndex = 0;
for (int i = 0; i < leftPart.length; i++) {
fullAddress[leftPartIndex] = leftPart[i];
leftPartIndex++;
}
int rightPartIndex = 7;
for (int i = rightPart.length - 1; i >= 0; i--) {
fullAddress[rightPartIndex] = rightPart[i];
rightPartIndex--;
}
for (int i = 0; i < 8; i++) {
if (fullAddress[i] == null || fullAddress[i].isEmpty()) {
fullAddress[i] = "0000";
} else {
fullAddress[i] = String.format("%4s", fullAddress[i]).replace(' ', '0');
}
}
return String.join(":", fullAddress);
}
::
기준으로 입력된 IPv6 주소를 분할하여 좌측 부분과 우측 부분을 나누고, 전체 8개의 섹션을 갖도록 확장합니다.
3. 세부 로직 분석
3.1 좌측 및 우측 부분 분리
String[] parts = ipv6Address.split("::", -1);
String[] leftPart = parts[0].split(":");
String[] rightPart = (parts.length == 2 && !parts[1].isEmpty()) ? parts[1].split(":") : new String[0];
::
을 기준으로 좌측과 우측 부분을 분리합니다. 우측 부분이 존재하는 경우에만 이를 분리하여 배열로 저장합니다.
3.2 좌측 부분 채우기
for (int i = 0; i < leftPart.length; i++) {
fullAddress[leftPartIndex] = leftPart[i];
leftPartIndex++;
}
- 좌측 부분을 확장된 IPv6 주소 배열에 채웁니다.
3.3 우측 부분 채우기
int rightPartIndex = 7;
for (int i = rightPart.length - 1; i >= 0; i--) {
fullAddress[rightPartIndex] = rightPart[i];
rightPartIndex--;
}
- 우측 부분을 확장된 IPv6 주소 배열의 끝에서부터 채웁니다.
3.4 빈 부분 채우기
for (int i = 0; i < 8; i++) {
if (fullAddress[i] == null || fullAddress[i].isEmpty()) {
fullAddress[i] = "0000";
} else {
fullAddress[i] = String.format("%4s", fullAddress[i]).replace(' ', '0');
}
}
- 빈 부분을 "0000"으로 채우고, 각 섹션을 4자리로 맞춥니다.
4. 테스트 케이스
// 출력 : 0025:0009:1985:00aa:0091:4846:0374:00bb
static String input1() { return "25:09:1985:aa:091:4846:374:bb"; }
// 출력 : 0000:0000:0000:0000:0000:0000:0000:0001
static String input2() { return "::1"; }
// 출력 : 0000:0000:0001:0002:0003:0004:0005:0006
static String input3() { return "::1:2:3:4:5:6"; }
// 출력 : 2001:db8:85a3:0000:0000:8a2e:0370:7334
static String input4() { return "2001:db8:85a3::8a2e:370:7334"; }
// 출력 : fe80:0000:0000:0000:0202:b3ff:fe1e:8329
static String input5() { return "fe80::202:b3ff:fe1e:8329"; }
// 출력 : 2001:0db8:0000:0000:0000:0000:0000:0001
static String input6() { return "2001:db8::1"; }
// 출력 : 0000:0000:0000:0000:0000:0000:0000:0001
static String input7() { return "::1"; }
// 출력 : 2001:0db8:0000:0042:0000:8a2e:0370:7334
static String input8() { return "2001:db8:0:42::8a2e:370:7334"; }
// 출력 : 0000:0000:0000:0000:0000:0000:0000:0000
static String input9() { return "::"; }
// 출력 : fe80:0000:0000:0000:0000:0000:0000:0001
static String input10() { return "fe80::1"; }
// 출력 : ff02:0000:0000:0000:0000:0000:0000:0001
static String input11() { return "ff02::1"; }
// 출력 : 2001:0db8:0000:0000:0000:0000:0000:0000
static String input13() { return "2001:db8::"; }
- 다양한 형태의 축약된 IPv6 주소를 테스트 케이스로 사용하여 확장된 IPv6 주소를 생성합니다.
5. 결론
이 프로그램은 다양한 형태의 축약된 IPv6 주소를 완전한 형태로 확장하는 기능을 효과적으로 수행합니다. 입력된 IPv6 주소를 ::
을 기준으로 좌우로 나누고, 각 부분을 확장하여 8개의 섹션으로 완성합니다.
5.1 향후 개선 사항
- 입력 검증 로직 추가: 유효하지 않은 입력에 대한 예외 처리를 추가할 수 있습니다.
- 코드 최적화: 반복문 및 조건문을 최적화하여 성능을 개선할 수 있습니다.
- 테스트 케이스 추가: 다양한 경계 조건 및 예외 상황에 대한 테스트 케이스를 추가하여 코드의 견고성을 높일 수 있습니다.
진행된 팀 스터디에서 얻은 인사이트는 무엇인가요?
CS면접을 이제 오후 5시부터 6시까지 하게 된다. 준비시간은 5시부터 5:30분부터이고 말하기 연습시간은 5시30분부터 6시까지 3개의 문제를 상대 페어와 말하게 된다. 이를 통해서 CS면접에 대한 자신감과 기존 알지 못했던 CS지식의 지식을 넓히고 깊게 탐구 할 수 있을 것이다
'스케쥴 > 스터디' 카테고리의 다른 글
[항해99 취업리부트 TIL] 3주차 2일 (0) | 2024.06.06 |
---|---|
[항해99 취업리부트 TIL] 3주차 1일 (0) | 2024.06.05 |
[항해99 취업리부트 TIL] 2주차 4일 (0) | 2024.06.01 |
[항해99 취업리부트 TIL] 2주차 3일 (0) | 2024.05.31 |
[항해99 취업 리부트 TIL] 2주차 2일 (1) | 2024.05.30 |