본문 바로가기
알고리즘 풀이/백준

[Gold V] IPv6 - 3107 (Java)

by cornsilk-tea 2023. 8. 19.

문제 요약

IPv6은 길이가 128비트인 차세대 인터넷 프로토콜이다.

IPv6의 주소는 32자리의 16진수를 4자리씩 끊어 나타낸다. 이때, 각 그룹은 콜론 (:)으로 구분해서 나타낸다.

예를 들면, 다음과 같다.

2001:0db8:85a3:0000:0000:8a2e:0370:7334
32자리의 16진수는 사람이 읽고 쓰기에 불편하고, 대부분의 자리가 0이기 때문에 아래와 같이 축약할 수 있다.

각 그룹의 앞자리의 0의 전체 또는 일부를 생략 할 수 있다. 위의 IPv6을 축약하면, 다음과 같다
2001:db8:85a3:0:00:8a2e:370:7334
만약 0으로만 이루어져 있는 그룹이 있을 경우 그 중 한 개 이상 연속된 그룹을 하나 골라 콜론 2개(::)로 바꿀 수 있다.
2001:db8:85a3::8a2e:370:7334
2번째 규칙은 모호함을 방지하기 위해서 오직 한 번만 사용할 수 있다.

올바른 축약형 IPv6주소가 주어졌을 때, 이를 원래 IPv6 (32자리의 16진수)로 복원하는 프로그램을 작성하시오.


문제 분석

  • IPv6 주소를 ":"으로 나누어 각 문자열을 리스트에 저장한다.
  • 각 문자열의 길이에 따라 "0"을 앞에 추가하여 다시저장한다.
  • "::"이 나올 때의 세 가지 경우를 고려하여 주소를 변환한다.
  • "::"이 맨 앞에 있는 경우: "::1234:5678"
    • 맨 앞의 "::"을 처리하고, 나머지 문자열의 개수를 세어서 필요한 만큼 "0000"를 삽입한다.
  • "::"이 중간에 있는 경우: "1234::5678"
    • "::"을 기준으로 리스트를 나누고, 각 부분의 문자열을 조합하여 완전한 주소를 삽입한다..
  • "::"이 맨 뒤에 있는 경우: "1234:5678::"
    • 맨 뒤의 "::"을 처리하고, 나머지 문자열의 개수를 세어서 필요한 만큼 "0000" 문자열을 삽입한다.

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

public class Main {
    static String[] zeroString = {"","0","00","000","0000"};
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        List<String> list = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        // split으로 나누면 ::의 경우 빈칸으로 나온다.
        for(String s : br.readLine().split(":")){
            if(!s.equals("")){
                s = zeroString[4-s.length()] + s;
            }
            list.add(s);
        }
//        System.out.println(list);
        if(list.size() == 0){
            System.out.println("0000:0000:0000:0000:0000:0000:0000:0000");
            return;
        }
        int coloneIdx = -1;
        coloneIdx = list.indexOf("");
        if(list.size() == 8 && coloneIdx == -1){
            System.out.println(makeFullIpAdd(list, sb));
            return;
        }
        // ::가 맨 앞에있을때(list의 맨 앞이 ""임)
        // ::1
        //[, , 0001]
        if(list.get(0).equals("")){
//            System.out.println("::가 맨 앞에있을때");
            list.remove(coloneIdx);
            while(list.size() <= 8){
                list.add(coloneIdx, zeroString[4]);
            }
        }
        // ::가 맨 뒤에있을때(colon값의 변도잉 없지만 list.size가 8이 아님)
        // 1::
        //[0001]
        else if(list.size() != 8 && coloneIdx == -1){
//            System.out.println("::가 맨 뒤에있을때");
            while(list.size() < 8){
                list.add(zeroString[4]);
            }
        }
        // ::가 중간에 있을때
        else{
            while(list.size() <= 8){
                list.add(coloneIdx, zeroString[4]);
            }
        }

        System.out.println(makeFullIpAdd(list, sb));

    }

    private static String makeFullIpAdd(List<String> list, StringBuilder sb) {
        for(int i = 0; i < list.size(); i++){
            if(!list.get(i).equals("")){
                sb.append(list.get(i));
                if(i != list.size()-1){
                    sb.append(":");
                }
            }
        }
        return sb.toString();
    }
}

정리

개선할 점

문제의 조건분기를 설정하고 해결하는데 시간이 오래 걸렸다. 좀 더 분석적으로 접근할 필요성이 있다.