이 글은 새로 배우면서 익히는 정보들을 기억하기 위한 글이며, 아래 내용들은 "kotlin IN ACTION" 책에서 발췌해온 내용과 개인적인 생각을 넣은 내용입니다.

문자열 나누기

자바 split 메서드로는 점(.)을 이용하여 문자열을 분리할 수 없다. 그 이유는 split의 구분 문자열은 실제로 정규식이기 때문이다.
정규식에서는 마침표(.)가 모든 문자를 나타낸다.

코틀린에서는 자바의 split 대신에 여러 가지 다른 조합의 파라미터를 받는 split 확장 함수를 제공함으로써 혼동을 야기하는 메서드를 감춘다. 정규식을 파라미터로 받는 함수는 String이 아닌 Regex 타입의 값을 받는다.

>>> println("12.345-6.A".split("\\. |-".toRegex()) // 정규식을 명시적으로 만든다.
[12, 345, 6, A]

코틀린의 정규식 문법은 자바와 똑같다. 뿐만 아니라 꼭 정규식을 사용할 필요 없이 split 확장 함수를 이용하여 하나 이상의 인자를 넣을 수 있다.

>> println(12.345-6.A".split(".", "-")) // println(12.345-6.A".split('.', '-'))
[12, 345, 6, A]

문자열이나 문자를 넣어도 마찬가지 결과가 나온다.

- kotlin IN ACTION 129 ~ 130p -

정규식과 3중 따옴표로 묶은 문자열

val path = "/Users/yole/kotlin-book/chapter.adoc"

위의 전체 경로 명을 String 확장 함수를 통해 구분 할 수 있다.

val directory = path.substringBeforeLast("/") // /Users/yole/kotlin-book
val fullName = path.substringAfterLast("/") // chapter.adoc
val fileName = fullName.substringBeforeLast(".") // chapter
val extension = fullName.substringAfterLast(".) // adoc

3중 따옴표 문자열을 사용하여 정규식을 만들수 있다.

val regex = """(.+)/(.+)\.(.+)""".toRegex()

3중 따옴표 문자열은 역슬래시(\)를 포함한 어떤 문자도 이스케이프할 필요가 없다. 마침표 기호를 이스케이프 하려면 \\. 라고 써야 하지만, 3중 따옴표 문자열에서는 \.라고 쓰면 된다.

- kotlin IN ACTION 130 ~ 133p -

'개발 언어 > Kotlin' 카테고리의 다른 글

Kotlin 함수 정의와 호출  (0) 2022.01.11
Kotlin 기초  (0) 2021.12.31
문제 링크 : https://www.acmicpc.net/problem/9012
문제 등급 : Silver IV
 

9012번: 괄호

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고

www.acmicpc.net

문제 해결 로직

  1. 문자열을 하나씩 Que에 넣는다.
  2. Que에 넣은 문자열과 앞으로 넣을 문자열을 비교하여 합이 맞는 괄호 인지 체크한다.
  3. 합이 맞는 괄호라면 que의 최상단 값을 제거한다.
  4. 합이 맞지 않는 괄호라면 que에 삽입한다.
  5. 문자열의 길이만큼 반복문이 다 돌고 que에 남아있는 문자가 있는지 확인하고 VPS인지 파악하여 결과를 출력한다.

이 문제는 타자 검정 같은 기본적인 문제이다. 지금 이 문제를 푸는 데에도 5분이 안 걸린 것 같다. 하지만 같은 유형의 문제가 기업 코딩 테스트에 나왔는데 결국 해결해내지 못했다. 응용이 안됬던 것일까? 긴장을 한 것일까?

푸념을 하며 나의 실수를 채찍질한다. 다음에는 이런 실수를 하지 않기를 빌며..

이 글을 보는 여러분들은 저와 같은 실수를 하지 않기를... 바랍니다.

 

아래와 같이 소스를 공유합니다.

public class 괄호 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        int n = Integer.parseInt(br.readLine());

        for(int i = 0; i < n; i++) {
            String[] s = br.readLine().split("");
            Queue<String> que = new LinkedList<>();
            for (int j = 0; j < s.length; j++) {
                if(que.isEmpty()) {
                    que.add(s[j]);
                }else {
                    if(que.peek().equals("(") && s[j].equals(")")) {
                        que.poll();
                    }else {
                        que.add(s[j]);
                    }
                }
            }
            if(que.isEmpty()) sb.append("YES").append("\n");
            else sb.append("NO").append("\n");
        }

        System.out.println(sb.toString());
    }
}
문제 링크 : https://www.acmicpc.net/problem/1541
문제 등급 : Silver II
 

1541번: 잃어버린 괄호

첫째 줄에 식이 주어진다. 식은 ‘0’~‘9’, ‘+’, 그리고 ‘-’만으로 이루어져 있고, 가장 처음과 마지막 문자는 숫자이다. 그리고 연속해서 두 개 이상의 연산자가 나타나지 않고, 5자리보다

www.acmicpc.net

문제 해결 로직

  1. 문자열을 '-' 기준으로 자른다.
  2. 자른 배열의 요소를 '+' 기준으로 자른다.
  3. +배열을 하나씩 더하고 - 를 한다.

이 문제는 +를 먼저 하고 -을 나중에 하여 큰 수를 빼주면 가장 작은 수를 구할 수 있는 문제이다.

 

아래와 같이 소스를 공유합니다.

public class 잃어버린 괄호 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String[] str = br.readLine().split("-");

        long res = Integer.MAX_VALUE;

        for(int i = 0; i < str.length; i++) {
            String[] s = str[i].split("\\+");
            
            long temp = 0;
            
            for(int j = 0; j < s.length; j++) {
                temp += Long.parseLong(s[j]);
            }
            
            if(res == Integer.MAX_VALUE) {
                res = temp;
            }else {
                res -= temp;
            }
        }

        System.out.println(res);
    }
}
문제 링크 : https://www.acmicpc.net/problem/5052

처음 전화번호 목록 문제를 접했을 때 이중 포문을 이용하여 시간 초과가 발생했다.

어떤 방법이 있을까 하고 고민할 때 스터디원이 Trie 자료구조를 사용하면 풀 수 있다고 힌트를 주었다.

하지만 Trie 자료구조를 모르고 있었기에 학습하여 문제를 해결하였고 Trie 자료구조를 이용하지 않더라도 풀 수 있는 방법이 있길래 Trie 자료구조를 사용하지 않는 방법으로 문제를 풀어보았다.

 

아래와 같이 소스를 공유한다.

 

Trie 자료구조를 이용한 구현

public class 전화번호목록 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringBuilder sb = new StringBuilder();
		
		int T = Integer.parseInt(br.readLine());
		
		for (int e = 0; e < T; e++) {
			int ca = Integer.parseInt(br.readLine());
			List<String> list = new ArrayList<>();
			Trie t = new Trie();
			
			for (int i = 0; i < ca; i++) {
				String word = br.readLine();
				list.add(word);
				t.insert(word);
			}
			
			boolean is = false;
			
			for(String k : list) {
				if(t.contains(k)) {
					is = true;
					break;
				}
			}
			
			sb.append((is == true) ? "NO":"YES").append("\n");
		}
		
        bw.write(sb.toString());
        bw.flush();
        bw.close();
	}
}

public class Trie {
	private TrieNode rootNode;
	
	public Trie() {
		this.rootNode = new TrieNode();
	}
	
	public void insert(String word) {
		TrieNode root = this.rootNode;
		
		for (int i = 0; i < word.length(); i++) {
			root = root.getChildNodes().computeIfAbsent(word.charAt(i), c -> new TrieNode());
		}
		root.setIsLastChar(true);
	}
	
	public boolean contains(String word) {
		TrieNode temp = this.rootNode;
		
		for (int i = 0; i < word.length(); i++) {
			char ch = word.charAt(i);
			TrieNode node = temp.getChildNodes().get(ch);
			
			if(node == null) return false;
			
			temp = node;
		}
		
		if(temp.isLastChar()) {
			if(temp.getChildNodes().isEmpty()) {
				return false;
			}
		}
		
		return true;
	}
	
	public void delete(String word) {
		delete(this.rootNode, word, 0);
	}
	
	public void delete(TrieNode node, String word, int idx) {
		char ch = word.charAt(idx);
		
		if(!node.getChildNodes().containsKey(ch)) throw new Error(word + " : 존재하지 않습니다.");
		
		TrieNode child = node.getChildNodes().get(ch);
		idx++;
		
		if(idx == word.length()) {
			if(!child.isLastChar()) throw new Error(word + " : 존재하지 않습니다.");
			
			child.setIsLastChar(false);
			
			if(child.getChildNodes().isEmpty()) node.getChildNodes().remove(ch);
		}else {
			delete(child, word, idx);
			
			if(!child.isLastChar() && child.getChildNodes().isEmpty()) node.getChildNodes().remove(ch);
		}
	}
	
	public boolean isRootEmpty() {
		return this.rootNode.getChildNodes().isEmpty();
	}
}

public class TrieNode {
	private Map<Character, TrieNode> childNodes = new HashMap<>();
	private boolean isLastChar;
	
	Map<Character, TrieNode> getChildNodes() {
		return this.childNodes;
	}
	
	boolean isLastChar() {
		return this.isLastChar;
	}
	
	void setIsLastChar(boolean is) {
		this.isLastChar = is;
	}
}

Trie 자료구조는 트리 형식으로 문자열을 찾는 자료구조이다.

Trie 자료구조를 이용하지 않은 구현

public class 전화번호목록 {
	public static Comparator<String> compare = new Comparator<>() {

		@Override
		public int compare(String o1, String o2) {
			return o1.compareTo(o2);
		}
		
	};
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int T = Integer.parseInt(br.readLine());
		
		for (int e = 0; e < T; e++) {
			int c = Integer.parseInt(br.readLine());
			
			List<String> list = new ArrayList<>();
			
			for (int i = 0; i < c; i++) {
				list.add(br.readLine());
			}
			
			Collections.sort(list, compare);
			boolean is = false;
			for (int i = 1; i < c; i++) {
				if(list.get(i).startsWith(list.get(i-1))) {
					is = true;
					break;
				}
			}
			
			System.out.println((is == true) ? "NO":"YES");
		}
	}
}

주어지는 문자들을 정렬하고 startsWith 함수를 이용하여 비교한다.

 

 

문제를 푸는 방식이 다양하여 한 가지 문제를 풀더라도 여러 방법으로 풀어 다양한 접근 방식을 습득하려고 노력중이다.

 


참고 자료

 

[자료구조] Trie(트라이)-2 : 자바로 구현하기

안녕하세요. 개발개입니다. 지난 시간 기초 개념에 이어, Trie를 자바로 구현하는 과정을 알아보겠습니다. 구현 과정에서 람다를 사용하기 때문에 Java8 베이스로 진행합니다. [KR/자료구조] - [자료

the-dev.tistory.com

 

[백준/5052번] 전화번호 목록(NCPC 2007)[Java]

문제 전화번호 목록이 주어진다. 이때, 이 목록이 일관성이 있는지 없는지를 구하는 프로그램을 작성하시오. 전화번호 목록이 일관성을 유지하려면, 한 번호가 다른 번호의 접두어인 경우가 없

blue-boy.tistory.com

 

+ Recent posts