diff --git a/src/class08_13/Code01_IsCBT.java b/src/class08_13/Code01_IsCBT.java index a98c382..63924d7 100644 --- a/src/class08_13/Code01_IsCBT.java +++ b/src/class08_13/Code01_IsCBT.java @@ -30,9 +30,7 @@ public class Code01_IsCBT { r = head.right; if ( // 如果遇到了不双全的节点之后,又发现当前节点不是叶节点 - (leaf && (l != null || r != null)) - || - (l == null && r != null) + (leaf && (l != null || r != null)) || (l == null && r != null) ) { return false; @@ -51,13 +49,9 @@ public class Code01_IsCBT { } public static boolean isCBT2(Node head) { - if (head == null) { - return true; - } return process(head).isCBT; } - // 对每一棵子树,是否是满二叉树、是否是完全二叉树、高度 public static class Info { public boolean isFull; public boolean isCBT; @@ -70,49 +64,23 @@ public class Code01_IsCBT { } } - public static Info process(Node X) { - if (X == null) { + public static Info process(Node x) { + if (x == null) { return new Info(true, true, 0); } - Info leftInfo = process(X.left); - Info rightInfo = process(X.right); - - - + Info leftInfo = process(x.left); + Info rightInfo = process(x.right); int height = Math.max(leftInfo.height, rightInfo.height) + 1; - - - boolean isFull = leftInfo.isFull - && - rightInfo.isFull - && leftInfo.height == rightInfo.height; - - + boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height; boolean isCBT = false; - if (isFull) { + if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height) { + isCBT = true; + } else if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) { + isCBT = true; + } else if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) { + isCBT = true; + } else if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) { isCBT = true; - } else { // 以x为头整棵树,不满 - if (leftInfo.isCBT && rightInfo.isCBT) { - - - if (leftInfo.isCBT - && rightInfo.isFull - && leftInfo.height == rightInfo.height + 1) { - isCBT = true; - } - if (leftInfo.isFull - && - rightInfo.isFull - && leftInfo.height == rightInfo.height + 1) { - isCBT = true; - } - if (leftInfo.isFull - && rightInfo.isCBT && leftInfo.height == rightInfo.height) { - isCBT = true; - } - - - } } return new Info(isFull, isCBT, height); } diff --git a/src/class08_13/Code03_lowestAncestor.java b/src/class08_13/Code03_lowestAncestor.java index ddab0a3..48eb66c 100644 --- a/src/class08_13/Code03_lowestAncestor.java +++ b/src/class08_13/Code03_lowestAncestor.java @@ -49,49 +49,41 @@ public class Code03_lowestAncestor { } } - public static Node lowestAncestor2(Node head, Node o1, Node o2) { - return process(head, o1, o2).ans; + public static Node lowestAncestor2(Node head, Node a, Node b) { + return process(head, a, b).ans; } - // 任何子树, public static class Info { + public boolean findA; + public boolean findB; public Node ans; - public boolean findO1; - public boolean findO2; - public Info(Node a, boolean f1, boolean f2) { - ans = a; - findO1 = f1; - findO2 = f2; + public Info(boolean fA, boolean fB, Node an) { + findA = fA; + findB = fB; + ans = an; } } - public static Info process(Node X, Node o1, Node o2) { - if (X == null) { - return new Info(null, false, false); + public static Info process(Node x, Node a, Node b) { + if (x == null) { + return new Info(false, false, null); } - Info leftInfo = process(X.left, o1, o2); - Info rightInfo = process(X.right, o1, o2); - boolean findO1 = X == o1 || leftInfo.findO1 || rightInfo.findO1; - boolean findO2 = X == o2 || leftInfo.findO2 || rightInfo.findO2; - // O1和O2最初的交汇点在哪? - // 1) 在左树上已经提前交汇了 - // 2) 在右树上已经提前交汇了 - // 3) 没有在左树或者右树上提前交汇,O1 O2 全了 - // 4) + Info leftInfo = process(x.left, a, b); + Info rightInfo = process(x.right, a, b); + boolean findA = (x == a) || leftInfo.findA || rightInfo.findA; + boolean findB = (x == b) || leftInfo.findB || rightInfo.findB; Node ans = null; if (leftInfo.ans != null) { ans = leftInfo.ans; - } - if (rightInfo.ans != null) { + } else if (rightInfo.ans != null) { ans = rightInfo.ans; - } - if (ans == null) { - if (findO1 && findO2) { - ans = X; + } else { + if (findA && findB) { + ans = x; } } - return new Info(ans, findO1, findO2); + return new Info(findA, findB, ans); } // for test diff --git a/src/class08_13/Code04_MaxHappy.java b/src/class08_13/Code04_MaxHappy.java index c433d36..4cc0b57 100644 --- a/src/class08_13/Code04_MaxHappy.java +++ b/src/class08_13/Code04_MaxHappy.java @@ -46,36 +46,34 @@ public class Code04_MaxHappy { } } - public static int maxHappy2(Employee boss) { - if (boss == null) { - return 0; - } - Info all = process2(boss); - return Math.max(all.yes, all.no); + public static int maxHappy2(Employee head) { + Info allInfo = process(head); + return Math.max(allInfo.no, allInfo.yes); } public static class Info { - public int yes; public int no; + public int yes; - public Info(int y, int n) { - yes = y; + public Info(int n, int y) { no = n; + yes = y; } } - public static Info process2(Employee x) { - if (x.nexts.isEmpty()) { - return new Info(x.happy, 0); + public static Info process(Employee x) { + if (x == null) { + return new Info(0, 0); } - int yes = x.happy; int no = 0; + int yes = x.happy; for (Employee next : x.nexts) { - Info nextInfo = process2(next); + Info nextInfo = process(next); + no += Math.max(nextInfo.no, nextInfo.yes); yes += nextInfo.no; - no += Math.max(nextInfo.yes, nextInfo.no); + } - return new Info(yes, no); + return new Info(no, yes); } // for test diff --git a/src/class09_13/Code01_LowestLexicography.java b/src/class09_13/Code01_LowestLexicography.java index 8d2157f..08dbd52 100644 --- a/src/class09_13/Code01_LowestLexicography.java +++ b/src/class09_13/Code01_LowestLexicography.java @@ -1,9 +1,8 @@ package class09_13; -import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.HashSet; +import java.util.TreeSet; public class Code01_LowestLexicography { @@ -11,34 +10,41 @@ public class Code01_LowestLexicography { if (strs == null || strs.length == 0) { return ""; } - ArrayList all = new ArrayList<>(); - HashSet use = new HashSet<>(); - process(strs, use, "", all); - String lowest = all.get(0); - for (int i = 1; i < all.size(); i++) { - if (all.get(i).compareTo(lowest) < 0) { - lowest = all.get(i); + TreeSet ans = process(strs); + return ans.size() == 0 ? "" : ans.first(); + } + + // strs中所有字符串全排列,返回所有可能的结果 + public static TreeSet process(String[] strs) { + TreeSet ans = new TreeSet<>(); + if (strs.length == 0) { + ans.add(""); + return ans; + } + for (int i = 0; i < strs.length; i++) { + String first = strs[i]; + String[] nexts = removeIndexString(strs, i); + TreeSet next = process(nexts); + for (String cur : next) { + ans.add(first + cur); } } - return lowest; + return ans; } - // strs里放着所有的字符串 - // 已经使用过的字符串的下标,在use里登记了,不要再使用了 - // 之前使用过的字符串,拼接成了-> path - // 用all收集所有可能的拼接结果 - public static void process(String[] strs, HashSet use, String path, ArrayList all) { - if (use.size() == strs.length) { - all.add(path); - } else { - for (int i = 0; i < strs.length; i++) { - if (!use.contains(i)) { - use.add(i); - process(strs, use, path + strs[i], all); - use.remove(i); - } + // {"abc", "cks", "bct"} + // 0 1 2 + // removeIndexString(arr , 1) -> {"abc", "bct"} + public static String[] removeIndexString(String[] arr, int index) { + int N = arr.length; + String[] ans = new String[N - 1]; + int ansIndex = 0; + for (int i = 0; i < N; i++) { + if (i != index) { + ans[ansIndex++] = arr[i]; } } + return ans; } public static class MyComparator implements Comparator { @@ -91,13 +97,7 @@ public class Code01_LowestLexicography { public static void main(String[] args) { int arrLen = 6; int strLen = 5; - int testTimes = 100000; - String[] arr = generateRandomStringArray(arrLen, strLen); - System.out.println("先打印一个生成的字符串"); - for (String str : arr) { - System.out.print(str + ","); - } - System.out.println(); + int testTimes = 10000; System.out.println("test begin"); for (int i = 0; i < testTimes; i++) { String[] arr1 = generateRandomStringArray(arrLen, strLen); diff --git a/src/class09_14/Code01_Light.java b/src/class09_14/Code01_Light.java index 05340eb..0dba03a 100644 --- a/src/class09_14/Code01_Light.java +++ b/src/class09_14/Code01_Light.java @@ -18,16 +18,14 @@ public class Code01_Light { if (index == str.length) { // 结束的时候 for (int i = 0; i < str.length; i++) { if (str[i] != 'X') { // 当前位置是点的话 - if (!lights.contains(i - 1) - && !lights.contains(i) - && !lights.contains(i + 1)) { + if (!lights.contains(i - 1) && !lights.contains(i) && !lights.contains(i + 1)) { return Integer.MAX_VALUE; } } } return lights.size(); } else { // str还没结束 - // i X . + // i X . int no = process(str, index + 1, lights); int yes = Integer.MAX_VALUE; if (str[index] == '.') { @@ -41,20 +39,20 @@ public class Code01_Light { public static int minLight2(String road) { char[] str = road.toCharArray(); - int index = 0; + int i = 0; int light = 0; - while (index < str.length) { - if (str[index] == 'X') { - index++; - } else { // i -> . + while (i < str.length) { + if (str[i] == 'X') { + i++; + } else { light++; - if (index + 1 == str.length) { + if (i + 1 == str.length) { break; - } else { - if (str[index + 1] == 'X') { - index = index + 2; + } else { // 有i位置 i+ 1 X . + if (str[i + 1] == 'X') { + i = i + 2; } else { - index = index + 3; + i = i + 3; } } } diff --git a/src/class09_14/Code02_LessMoneySplitGold.java b/src/class09_14/Code02_LessMoneySplitGold.java index 38c51b6..8f50521 100644 --- a/src/class09_14/Code02_LessMoneySplitGold.java +++ b/src/class09_14/Code02_LessMoneySplitGold.java @@ -4,6 +4,7 @@ import java.util.PriorityQueue; public class Code02_LessMoneySplitGold { + // 纯暴力! public static int lessMoney1(int[] arr) { if (arr == null || arr.length == 0) { return 0; @@ -11,6 +12,8 @@ public class Code02_LessMoneySplitGold { return process(arr, 0); } + // 等待合并的数都在arr里,pre之前的合并行为产生了多少总代价 + // arr中只剩一个数字的时候,停止合并,返回最小的总代价 public static int process(int[] arr, int pre) { if (arr.length == 1) { return pre; diff --git a/src/class09_14/Code03_BestArrange.java b/src/class09_14/Code03_BestArrange.java index b67be4f..3d4fe4b 100644 --- a/src/class09_14/Code03_BestArrange.java +++ b/src/class09_14/Code03_BestArrange.java @@ -15,6 +15,7 @@ public class Code03_BestArrange { } } + // 暴力!所有情况都尝试! public static int bestArrange1(Program[] programs) { if (programs == null || programs.length == 0) { return 0; @@ -22,8 +23,8 @@ public class Code03_BestArrange { return process(programs, 0, 0); } - // 还剩什么会议都放在programs里 - // done 之前已经安排了多少会议,数量 + // 还剩下的会议都放在programs里 + // done之前已经安排了多少会议的数量 // timeLine目前来到的时间点是什么 // 目前来到timeLine的时间点,已经安排了done多的会议,剩下的会议programs可以自由安排 @@ -32,7 +33,7 @@ public class Code03_BestArrange { if (programs.length == 0) { return done; } - // 还有会议可以选择 + // 还剩下会议 int max = done; // 当前安排的会议是什么会,每一个都枚举 for (int i = 0; i < programs.length; i++) { @@ -55,10 +56,12 @@ public class Code03_BestArrange { return ans; } + // 会议的开始时间和结束时间,都是数值,不会 < 0 public static int bestArrange2(Program[] programs) { Arrays.sort(programs, new ProgramComparator()); int timeLine = 0; int result = 0; + // 依次遍历每一个会议,结束时间早的会议先遍历 for (int i = 0; i < programs.length; i++) { if (timeLine <= programs[i].start) { result++; diff --git a/src/class09_14/Code04_IPO.java b/src/class09_14/Code04_IPO.java index 0c42e96..eec4c97 100644 --- a/src/class09_14/Code04_IPO.java +++ b/src/class09_14/Code04_IPO.java @@ -5,6 +5,10 @@ import java.util.PriorityQueue; public class Code04_IPO { + // 最多K个项目 + // W是初始资金 + // Profits[] Capital[] 一定等长 + // 返回最终最大的资金 public static int findMaximizedCapital(int K, int W, int[] Profits, int[] Capital) { PriorityQueue minCostQ = new PriorityQueue<>(new MinCostComparator()); PriorityQueue maxProfitQ = new PriorityQueue<>(new MaxProfitComparator()); diff --git a/src/class10/Code01_UnionFind.java b/src/class09_14/Code05_UnionFind.java similarity index 78% rename from src/class10/Code01_UnionFind.java rename to src/class09_14/Code05_UnionFind.java index 6e12590..e1738c6 100644 --- a/src/class10/Code01_UnionFind.java +++ b/src/class09_14/Code05_UnionFind.java @@ -1,10 +1,10 @@ -package class10; +package class09_14; import java.util.HashMap; import java.util.List; import java.util.Stack; -public class Code01_UnionFind { +public class Code05_UnionFind { public static class Node { V value; @@ -31,14 +31,14 @@ public class Code01_UnionFind { } } - // 从点cur开始,一直往上找,找到不能再往上的代表点,返回 + // 给你一个节点,请你往上到不能再往上,把代表返回 public Node findFather(Node cur) { Stack> path = new Stack<>(); while (cur != parents.get(cur)) { path.push(cur); cur = parents.get(cur); } - // cur头节点 + // cur == parents.get(cur) while (!path.isEmpty()) { parents.put(path.pop(), cur); } @@ -46,16 +46,10 @@ public class Code01_UnionFind { } public boolean isSameSet(V a, V b) { - if (!nodes.containsKey(a) || !nodes.containsKey(b)) { - return false; - } return findFather(nodes.get(a)) == findFather(nodes.get(b)); } public void union(V a, V b) { - if (!nodes.containsKey(a) || !nodes.containsKey(b)) { - return; - } Node aHead = findFather(nodes.get(a)); Node bHead = findFather(nodes.get(b)); if (aHead != bHead) { @@ -68,6 +62,10 @@ public class Code01_UnionFind { sizeMap.remove(small); } } - } + public int sets() { + return sizeMap.size(); + } + + } } diff --git a/src/class09_14/Code06_IslandProblem.java b/src/class09_14/Code06_IslandProblem.java new file mode 100644 index 0000000..fa9c10d --- /dev/null +++ b/src/class09_14/Code06_IslandProblem.java @@ -0,0 +1,248 @@ +package class09_14; + +import java.util.ArrayList; +import java.util.List; + +import class09_14.Code05_UnionFind.UnionSet; + +public class Code06_IslandProblem { + + public static int solve1(int[][] board) { + int islands = 0; + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == 1) { + islands++; + infect(board, i, j); + } + } + } + return islands; + } + + public static void infect(int[][] board, int i, int j) { + if (i < 0 || i == board.length || j < 0 || j == board[0].length || board[i][j] != 1) { + return; + } + board[i][j] = 2; + infect(board, i - 1, j); + infect(board, i + 1, j); + infect(board, i, j - 1); + infect(board, i, j + 1); + } + + public static int solve2(int[][] board) { + int row = board.length; + int col = board[0].length; + Dot[][] dots = new Dot[row][col]; + List dotList = new ArrayList<>(); + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (board[i][j] == 1) { + dots[i][j] = new Dot(); + dotList.add(dots[i][j]); + } + } + } + UnionSet us = new UnionSet<>(dotList); + for (int j = 1; j < col; j++) { + if (board[0][j - 1] == 1 && board[0][j] == 1) { + us.union(dots[0][j - 1], dots[0][j]); + } + } + for (int i = 1; i < row; i++) { + if (board[i - 1][0] == 1 && board[i][0] == 1) { + us.union(dots[i - 1][0], dots[i][0]); + } + } + for (int i = 1; i < row; i++) { + for (int j = 1; j < col; j++) { + if (board[i][j] == 1) { + if (board[i][j - 1] == 1) { + us.union(dots[i][j - 1], dots[i][j]); + } + if (board[i - 1][j] == 1) { + us.union(dots[i - 1][j], dots[i][j]); + } + } + } + } + return us.sets(); + } + + public static class Dot { + + } + + public static int solve3(int[][] board) { + int row = board.length; + int col = board[0].length; + UnionFind uf = new UnionFind(board); + for (int j = 1; j < col; j++) { + if (board[0][j - 1] == 1 && board[0][j] == 1) { + uf.union(0, j - 1, 0, j); + } + } + for (int i = 1; i < row; i++) { + if (board[i - 1][0] == 1 && board[i][0] == 1) { + uf.union(i - 1, 0, i, 0); + } + } + for (int i = 1; i < row; i++) { + for (int j = 1; j < col; j++) { + if (board[i][j] == 1) { + if (board[i][j - 1] == 1) { + uf.union(i, j - 1, i, j); + } + if (board[i - 1][j] == 1) { + uf.union(i - 1, j, i, j); + } + } + } + } + return uf.sets(); + } + + public static class UnionFind { + private int[] parent; + private int[] size; + private int[] help; + private int col; + private int sets; + + public UnionFind(int[][] board) { + col = board[0].length; + sets = 0; + int row = board.length; + int len = row * col; + parent = new int[len]; + size = new int[len]; + help = new int[len]; + for (int r = 0; r < row; r++) { + for (int c = 0; c < col; c++) { + if (board[r][c] == 1) { + int i = index(r, c); + parent[i] = i; + size[i] = 1; + sets++; + } + } + } + } + + private int index(int r, int c) { + return r * col + c; + } + + private int find(int i) { + int hi = 0; + while (i != parent[i]) { + help[hi++] = i; + i = parent[i]; + } + for (hi--; hi >= 0; hi--) { + parent[help[hi]] = i; + } + return i; + } + + public void union(int r1, int c1, int r2, int c2) { + int i1 = index(r1, c1); + int i2 = index(r2, c2); + int f1 = find(i1); + int f2 = find(i2); + if (f1 != f2) { + if (size[f1] >= size[f2]) { + size[f1] += size[f2]; + parent[f2] = f1; + } else { + size[f2] += size[f1]; + parent[f1] = f2; + } + sets--; + } + } + + public int sets() { + return sets; + } + + } + + public static int[][] generateRandomMatrix(int row, int col) { + int[][] board = new int[row][col]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + board[i][j] = Math.random() < 0.5 ? 1 : 0; + } + } + return board; + } + + public static int[][] copy(int[][] board) { + int row = board.length; + int col = board[0].length; + int[][] ans = new int[row][col]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + ans[i][j] = board[i][j]; + } + } + return ans; + } + + public static void main(String[] args) { + int row = 0; + int col = 0; + int[][] board1 = null; + int[][] board2 = null; + int[][] board3 = null; + long start = 0; + long end = 0; + + row = 1000; + col = 1000; + board1 = generateRandomMatrix(row, col); + board2 = copy(board1); + board3 = copy(board1); + + System.out.println("感染方法、并查集(map实现)、并查集(数组实现)的运行结果和运行时间"); + System.out.println("随机生成的二维矩阵规模 : " + row + " * " + col); + + start = System.currentTimeMillis(); + System.out.println("感染方法的运行结果: " + solve1(board1)); + end = System.currentTimeMillis(); + System.out.println("感染方法的运行时间: " + (end - start) + " ms"); + + start = System.currentTimeMillis(); + System.out.println("并查集(map实现)的运行结果: " + solve2(board2)); + end = System.currentTimeMillis(); + System.out.println("并查集(map实现)的运行时间: " + (end - start) + " ms"); + + start = System.currentTimeMillis(); + System.out.println("并查集(数组实现)的运行结果: " + solve3(board3)); + end = System.currentTimeMillis(); + System.out.println("并查集(数组实现)的运行时间: " + (end - start) + " ms"); + + System.out.println(); + + row = 10000; + col = 10000; + board1 = generateRandomMatrix(row, col); + board3 = copy(board1); + System.out.println("感染方法、并查集(数组实现)的运行结果和运行时间"); + System.out.println("随机生成的二维矩阵规模 : " + row + " * " + col); + + start = System.currentTimeMillis(); + System.out.println("感染方法的运行结果: " + solve1(board1)); + end = System.currentTimeMillis(); + System.out.println("感染方法的运行时间: " + (end - start) + " ms"); + + start = System.currentTimeMillis(); + System.out.println("并查集(数组实现)的运行结果: " + solve3(board3)); + end = System.currentTimeMillis(); + System.out.println("并查集(数组实现)的运行时间: " + (end - start) + " ms"); + + } + +} diff --git a/src/class10/Code02_BFS.java b/src/class10/Code01_BFS.java similarity index 95% rename from src/class10/Code02_BFS.java rename to src/class10/Code01_BFS.java index cb87d5e..c219524 100644 --- a/src/class10/Code02_BFS.java +++ b/src/class10/Code01_BFS.java @@ -4,7 +4,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.Queue; -public class Code02_BFS { +public class Code01_BFS { // 从node出发,进行宽度优先遍历 public static void bfs(Node node) { diff --git a/src/class12/Code05_LongestCommonSubsequence.java b/src/class12/Code05_LongestCommonSubsequence.java new file mode 100644 index 0000000..e3360ee --- /dev/null +++ b/src/class12/Code05_LongestCommonSubsequence.java @@ -0,0 +1,58 @@ +package class12; + +// 这个问题leetcode上可以直接测 +// 链接:https://leetcode.com/problems/longest-common-subsequence/ +public class Code05_LongestCommonSubsequence { + + public static int longestCommonSubsequence1(String text1, String text2) { + if (text1 == null || text2 == null || text1.length() == 0 || text2.length() == 0) { + return 0; + } + return process(text1.toCharArray(), text2.toCharArray(), text1.length() - 1, text2.length() - 1); + } + + // str1[0..i]与str2[0..j]最长公共子序列多长 + public static int process(char[] str1, char[] str2, int i, int j) { + if (i == 0 && j == 0) { + return str1[0] == str2[0] ? 1 : 0; + } + if (i == 0) { + return str1[0] == str2[j] ? 1 : process(str1, str2, 0, j - 1); + } + if (j == 0) { + return str1[i] == str2[0] ? 1 : process(str1, str2, i - 1, 0); + } + int p1 = process(str1, str2, i - 1, j); + int p2 = process(str1, str2, i, j - 1); + int p3 = str1[i] == str2[j] ? (process(str1, str2, i - 1, j - 1) + 1) : 0; + return Math.max(Math.max(p1, p2), p3); + } + + public static int longestCommonSubsequence2(String text1, String text2) { + if (text1 == null || text2 == null || text1.length() == 0 || text2.length() == 0) { + return 0; + } + char[] str1 = text1.toCharArray(); + char[] str2 = text2.toCharArray(); + int N = str1.length; + int M = str2.length; + int[][] dp = new int[N][M]; + dp[0][0] = str1[0] == str2[0] ? 1 : 0; + for (int i = 1; i < N; i++) { + dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0]; + } + for (int j = 1; j < M; j++) { + dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1]; + } + for (int i = 1; i < N; i++) { + for (int j = 1; j < M; j++) { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + if (str1[i] == str2[j]) { + dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1); + } + } + } + return dp[N - 1][M - 1]; + } + +}