|
| 1 | +import java.util.ArrayList; |
| 2 | +import java.util.Collections; |
| 3 | +import java.util.Comparator; |
| 4 | +import java.util.List; |
| 5 | + |
| 6 | +public class Geegong { |
| 7 | + |
| 8 | + /** |
| 9 | + * LIS, LCS 와 연관지어서 풀이 |
| 10 | + * 1. 먼저 text1을 훑어보는데 text1에 중복되는 알파벳이 있을 수 있기에 각 캐릭터별로 인덱스들을 저장 (각 원소가 arrayList가 있는 배열) |
| 11 | + * 2. text2 를 훑으면서 매칭되는 캐릭터들에 대해서만 1에서 저장된 인덱스들을 한 배열안에 나열 |
| 12 | + * -> 이떄 나열해서 넣을때마다 역순으로 집어넣는게 중요! (왜냐면 이 나열된 인덱스들을 가지고 LIS를 구할거라서) |
| 13 | + * 3. 나열된 인덱스들의 값들을 가지고 LIS 를 구한다, 즉 이 LIS의 길이가 LCS 의 길이가 된다..!! (와우 신기) |
| 14 | + * 그러나 leet code 에 돌렸을 때 runtime 이 영 좋지는 않음 |
| 15 | + * |
| 16 | + * time complexity : O(M + N logN) => text2에 대해서 문자마다 바이너리서치가 수행됨 |
| 17 | + * space complexity : O(M+N) |
| 18 | + * @param text1 |
| 19 | + * @param text2 |
| 20 | + * @return |
| 21 | + */ |
| 22 | + public int longestCommonSubsequence(String text1, String text2) { |
| 23 | + char[] chText1 = text1.toCharArray(); |
| 24 | + char[] chText2 = text2.toCharArray(); |
| 25 | + |
| 26 | + // text1만 각 원소 별로 char가 가지는 index를 array 로 갖는 배열을 생성 |
| 27 | + List<Integer>[] positionIndices = new List[26]; |
| 28 | + for (int index = 0; index<chText1.length; index++) { |
| 29 | + if (positionIndices[chText1[index] - 'a'] == null) { |
| 30 | + positionIndices[chText1[index] - 'a'] = new ArrayList(); |
| 31 | + positionIndices[chText1[index] - 'a'].add(index); |
| 32 | + } else { |
| 33 | + positionIndices[chText1[index] - 'a'].add(index); |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + |
| 38 | + // 여기서부터 LIS 를 구할것임 |
| 39 | + List<Integer> indices = new ArrayList<>(); |
| 40 | + for (int index=0; index<chText2.length; index++) { |
| 41 | + |
| 42 | + char find = chText2[index]; |
| 43 | + if (positionIndices[find-'a'] != null && positionIndices[find-'a'].size() > 0) { |
| 44 | + // 역순 (LIS 를 구하기 위해서 일부러 뒤집어 높음, 즉 각 char 별 LIS 를 구할것이기 때문에..) |
| 45 | + // positionIndices 에서 구했던 값들을 그대로 addAll 한다면 오름차순이 되기때문에 정확한 LIS 를 구할 수 없다 |
| 46 | + |
| 47 | + indices.addAll(positionIndices[find-'a'].stream().sorted(Comparator.reverseOrder()).toList()); |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + // find LIS |
| 52 | + return findLIS(indices).size(); |
| 53 | + } |
| 54 | + |
| 55 | + public List<Integer> findLIS(List<Integer> source) { |
| 56 | + if (source.size() == 0) { |
| 57 | + return source; |
| 58 | + } |
| 59 | + |
| 60 | + List<Integer> LISResult = new ArrayList<>(); |
| 61 | + for (int index=0; index<source.size(); index++) { |
| 62 | + int target = source.get(index); |
| 63 | + int insertionPosition = Collections.binarySearch(LISResult, target); |
| 64 | + //Returns: |
| 65 | + //the index of the search key, if it is contained in the list; |
| 66 | + // otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the list: |
| 67 | + if (insertionPosition < 0) { |
| 68 | + insertionPosition = -insertionPosition - 1; |
| 69 | + } |
| 70 | + |
| 71 | + if (LISResult.size() == insertionPosition) { |
| 72 | + LISResult.add(target); |
| 73 | + } else { |
| 74 | + LISResult.set(insertionPosition, target); |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + return LISResult; |
| 79 | + } |
| 80 | + |
| 81 | +} |
| 82 | + |
0 commit comments