题目

image.png

思路

  • 明确每次做动态规划的题目一定要用递归思路思考问题,如何把大问题分成小问题
  • 思路一:递归,定义recur(String text1, int i, String text2, int j)表示字符串text1前i和字符串text2前j的最大长度,每次比较我们只比较text1.charAt(i)是否等于text2.charAt(j)即可,是则加1,并且继续寻找下一个recur(text1,i+1,text2,j+1),如果不相等我们选择recur(text1,i+1,text2,j)和recur(text1,i,text2,j+1)的最大值
  • 思路二:备忘录
  • 思路三:动态规划,基于递归
  • 思路四:优化dp数组的动态规划,基于思路三

代码

  1. //1.暴力递归
  2. public int longestCommonSubsequence(String text1, String text2){
  3. return recur(text1, 0, text2, 0);
  4. }
  5. public int recur(String text1, int i, String text2, int j) {
  6. if (i >= text1.length() || j >= text2.length()) return 0;
  7. if (text1.charAt(i) == text2.charAt(j)) {
  8. return recur(text1, i + 1, text2, j + 1) + 1;
  9. } else {
  10. return Math.max(recur(text1, i, text2, j + 1), recur(text1, i + 1, text2, j));
  11. }
  12. }
  13. //2.备忘录
  14. int[][] dp;
  15. public int longestCommonSubsequence(String text1, String text2){
  16. dp = new int[text1.length()][text2.length()];
  17. for (int i = 0; i < text1.length(); i++) {
  18. for (int j = 0; j < text2.length(); j++) {
  19. dp[i][j] = -1;
  20. }
  21. }
  22. return recur(text1, 0, text2, 0);
  23. }
  24. public int recur(String text1, int i, String text2, int j) {
  25. if (i >= text1.length() || j >= text2.length()) return 0;
  26. if (dp[i][j] != -1) return dp[i][j];
  27. int res = 0;
  28. if (text1.charAt(i) == text2.charAt(j)) {
  29. res = recur(text1, i + 1, text2, j + 1) + 1;
  30. } else {
  31. res = Math.max(recur(text1, i, text2, j + 1), recur(text1, i + 1, text2, j));
  32. }
  33. dp[i][j] = res;
  34. return res;
  35. }
  36. //3.动态规划
  37. public int longestCommonSubsequence(String text1, String text2) {
  38. //dp[i][j]表示text1[0~i-1]与text2[0~j-1]的最大子序列长度,只是把备忘录的拿过来
  39. int[][] dp = new int[text1.length() + 1][text2.length() + 1];
  40. for (int i = 0; i <= text1.length(); i++) {
  41. dp[i][0] = 0;
  42. }
  43. for (int j = 0; j <= text2.length(); j++) {
  44. dp[0][j] = 0;
  45. }
  46. for (int i = 0; i < text1.length(); i++) {
  47. for (int j = 0; j < text2.length(); j++) {
  48. if (text1.charAt(i) == text2.charAt(j)) {
  49. dp[i + 1][j + 1] = dp[i][j] + 1;
  50. } else {
  51. dp[i + 1][j + 1] = Math.max(dp[i][j + 1], dp[i + 1][j]) ;
  52. }
  53. }
  54. }
  55. return dp[text1.length()][text2.length()];
  56. }
  57. //4.动态规划,优化dp数组,由于每次只用到前一列和前一个,因此可以优化为一维
  58. public int longestCommonSubsequence(String text1, String text2) {
  59. int[] dp = new int[text2.length() + 1];
  60. for (int j = 0; j <= text2.length(); j++) {
  61. dp[j] = 0;
  62. }
  63. for (int i = 0; i < text1.length(); i++) {
  64. for (int j = 0, prev = dp[0]; j < text2.length(); j++) {
  65. int t = dp[j + 1];
  66. if (text1.charAt(i) == text2.charAt(j)) {
  67. dp[j + 1] = prev + 1;
  68. } else {
  69. dp[j + 1] = Math.max(dp[j + 1], dp[j]) ;
  70. }
  71. prev = t;
  72. }
  73. }
  74. return dp[text2.length()];
  75. }

最大公共子序列