@@ -20,36 +20,91 @@ public class Geegong {
2020 * @return
2121 */
2222 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- }
23+
24+ /**
25+ * DP 를 이용한 LIS 구하기
26+ * 2차원 배열을 만들어 text1, text2 들을 하나씩 훑어가며
27+ * 이전에 일치했던 각 character 별로 횟수들을 기록해가며 더 LIS 로 붙일 수 있는지 정리해가는 기법
28+ * 참고 블로그 : https://velog.io/@emplam27/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-LCS-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Longest-Common-Substring%EC%99%80-Longest-Common-Subsequence
29+ * time complexity : O(M * N) => O (N)
30+ * space complexity : O(M * N) => O (N)
31+ */
32+ char [] ch1 = text1 .toCharArray ();
33+ char [] ch2 = text2 .toCharArray ();
34+
35+ int [][] LISArr = new int [ch1 .length + 1 ][ch2 .length + 1 ];
36+
37+ // first, fill zeros in first row, first column for convenient
38+ for (int idx =0 ; idx <=ch2 .length ; idx ++) {
39+ LISArr [0 ][idx ] = 0 ;
3540 }
3641
42+ for (int idx =0 ; idx <=ch1 .length ; idx ++) {
43+ LISArr [idx ][0 ] = 0 ;
44+ }
3745
38- // 여기서부터 LIS 를 구할것임
39- List < Integer > indices = new ArrayList <>();
40- for (int index = 0 ; index < chText2 .length ; index ++) {
46+ int maxLIS = 0 ;
47+ for ( int index1 = 0 ; index1 < ch1 . length ; index1 ++) {
48+ for (int index2 = 0 ; index2 < ch2 .length ; index2 ++) {
4149
42- char find = chText2 [index ];
43- if (positionIndices [find -'a' ] != null && positionIndices [find -'a' ].size () > 0 ) {
44- // 역순 (LIS 를 구하기 위해서 일부러 뒤집어 높음, 즉 각 char 별 LIS 를 구할것이기 때문에..)
45- // positionIndices 에서 구했던 값들을 그대로 addAll 한다면 오름차순이 되기때문에 정확한 LIS 를 구할 수 없다
50+ // if same, then
51+ if (ch1 [index1 ] == ch2 [index2 ]) {
52+ // LISArr 의 인덱스값이 +1 이 되는 이유는 LISArr 의 크기가 text1, text2 크기 + 1 만큼 만들었기 때문
53+ LISArr [index1 + 1 ][index2 + 1 ] = LISArr [index1 ][index2 ] + 1 ;
54+ } else {
55+ int biggerOne = Math .max (LISArr [index1 ][index2 + 1 ], LISArr [index1 + 1 ][index2 ]);
56+ LISArr [index1 + 1 ][index2 + 1 ] = biggerOne ;
57+ }
4658
47- indices . addAll ( positionIndices [ find - 'a' ]. stream (). sorted ( Comparator . reverseOrder ()). toList () );
59+ maxLIS = Math . max ( maxLIS , LISArr [ index1 + 1 ][ index2 + 1 ] );
4860 }
4961 }
5062
51- // find LIS
52- return findLIS (indices ).size ();
63+ return maxLIS ;
64+
65+
66+
67+ /**
68+ * LIS, LCS 와 연관지어서 풀이
69+ * 1. 먼저 text1을 훑어보는데 text1에 중복되는 알파벳이 있을 수 있기에 각 캐릭터별로 인덱스들을 저장 (각 원소가 arrayList가 있는 배열)
70+ * 2. text2 를 훑으면서 매칭되는 캐릭터들에 대해서만 1에서 저장된 인덱스들을 한 배열안에 나열
71+ * -> 이떄 나열해서 넣을때마다 역순으로 집어넣는게 중요! (왜냐면 이 나열된 인덱스들을 가지고 LIS를 구할거라서)
72+ * 3. 나열된 인덱스들의 값들을 가지고 LIS 를 구한다, 즉 이 LIS의 길이가 LCS 의 길이가 된다..!! (와우 신기)
73+ * 그러나 leet code 에 돌렸을 때 runtime 이 영 좋지는 않음
74+ *
75+ * time complexity : O(M + N logN) => text2에 대해서 문자마다 바이너리서치가 수행됨
76+ * space complexity : O(M+N)
77+ */
78+ // char[] chText1 = text1.toCharArray();
79+ // char[] chText2 = text2.toCharArray();
80+ //
81+ // // text1만 각 원소 별로 char가 가지는 index를 array 로 갖는 배열을 생성
82+ // List<Integer>[] positionIndices = new List[26];
83+ // for (int index = 0; index<chText1.length; index++) {
84+ // if (positionIndices[chText1[index] - 'a'] == null) {
85+ // positionIndices[chText1[index] - 'a'] = new ArrayList();
86+ // positionIndices[chText1[index] - 'a'].add(index);
87+ // } else {
88+ // positionIndices[chText1[index] - 'a'].add(index);
89+ // }
90+ // }
91+ //
92+ //
93+ // // 여기서부터 LIS 를 구할것임
94+ // List<Integer> indices = new ArrayList<>();
95+ // for (int index=0; index<chText2.length; index++) {
96+ //
97+ // char find = chText2[index];
98+ // if (positionIndices[find-'a'] != null && positionIndices[find-'a'].size() > 0) {
99+ // // 역순 (LIS 를 구하기 위해서 일부러 뒤집어 높음, 즉 각 char 별 LIS 를 구할것이기 때문에..)
100+ // // positionIndices 에서 구했던 값들을 그대로 addAll 한다면 오름차순이 되기때문에 정확한 LIS 를 구할 수 없다
101+ //
102+ // indices.addAll(positionIndices[find-'a'].stream().sorted(Comparator.reverseOrder()).toList());
103+ // }
104+ // }
105+ //
106+ // // find LIS
107+ // return findLIS(indices).size();
53108 }
54109
55110 public List <Integer > findLIS (List <Integer > source ) {
0 commit comments