Java both memoization and DP, O(n * n * k) solution
We have two parts in the problem\n1) How to find how many chars to change in a given string if it has to be palindrome\n     - If chars at given two start and e
We have two parts in the problem\n1) How to find how many chars to change in a given string if it has to be palindrome\n     - If chars at given two start and end indices are not equal, then you have to change one of them and also you need to change as many chars as needed to make start + 1 and end - 1 substring palindrome i.e., chars needed to make its inner string palindrome\n     - Otherwise, since both chars are equal, we dont need to touch them, but still you have to change chars needed for start + 1 and end - 1 substring to be palindrome\n\n\t```\n\tint[][] paldp = new int[s.length()][s.length()];\n\tfor(int end = 0; end < s.length(); end++){\n\t\tfor(int start = end; start >= 0; start--){\n\t\t   if(s.charAt(start) == s.charAt(end)){\n\t\t\t   if(end - start > 2) paldp[start][end] = paldp[start + 1][end - 1];\n\t\t   }else {\n\t\t\t   if(end - start <= 2) paldp[start][end] = 1;\n\t\t\t   else paldp[start][end] = 1 + paldp[start + 1][end - 1];\n\t\t   } \n\t\t}\n\t}\n\t```\n2) Now we need to find how to divide them into k strings such that cost of changing is minimum. Instead of saying divide them into k substrings, lets say **cut** them. **If you make a cut, that divides the string into two strings. So if you want to divide the string into k string, you need to make k - 1 cuts**.\n\n\t> For each substring starting at index 0 and ending at index i, make a cut there. Now the cost is cost of making a single cut from 0 to i (i.e., how many chars need to be changed to make this substring a palindrome, see #1) + cost of making remaining k - 1 cuts from i + 1 to end of string\n\t```\n\tInteger[][] kdp = new Integer[s.length()][k];\n\trec(s, 0, k - 1); // to make k substrings, we need to make k - 1 cuts\n\tprivate int rec(String s, int i, int k){\n        if(k == 0){ // if no cuts can be made\n            if(i == s.length()) return 0;\n            else return paldp[i][s.length() - 1]; // cost of last slice of string to make it a palindrome since we cannot make any further cuts\n        } \n        if(kdp[i][k] != null) return kdp[i][k];\n        int min = s.length();\n        for(int j = i; j < s.length() - 1; j++){\n            min = Math.min(min, paldp[i][j] + rec(s, j + 1, k - 1));\n        }\n        return kdp[i][k] = min;\n    }\n\t```\n\t\n\tNow combine above steps\n\n```\nint[][] paldp;\nInteger[][] kdp;\npublic int palindromePartition(String s, int k) {\n\tpaldp = new int[s.length()][s.length()];\n\tfor(int end = 0; end < s.length(); end++){\n\t\tfor(int start = end; start >= 0; start--){\n\t\t   if(s.charAt(start) == s.charAt(end)){\n\t\t\t   if(end - start > 2) paldp[start][end] = paldp[start + 1][end - 1];\n\t\t   }else {\n\t\t\t   if(end - start <= 2) paldp[start][end] = 1;\n\t\t\t   else paldp[start][end] = 1 + paldp[start + 1][end - 1];\n\t\t   } \n\t\t}\n\t}\n\tkdp = new Integer[s.length()][k];\n\treturn rec(s, 0, k - 1); // to make k substrings, we need to make k - 1 cuts\n}\n\nprivate int rec(String s, int i, int k){\n\tif(k == 0){ // if no cuts can be made\n\t\tif(i == s.length()) return 0;\n\t\telse return paldp[i][s.length() - 1]; // cost of last slice of string to make it a palindrome since we cannot make any further cuts\n\t} \n\tif(kdp[i][k] != null) return kdp[i][k];\n\tint min = s.length();\n\tfor(int j = i; j < s.length() - 1; j++){\n\t\tmin = Math.min(min, paldp[i][j] + rec(s, j + 1, k - 1));\n\t}\n\treturn kdp[i][k] = min;\n}\n```\n\nTime complexity: \n1) First step take O(n ^2) clearly\n2) In second step we make O(n^2) calls one for each substring of length l starting at index i. Look at the for loop. For a given index j, it will be called recursively for j+ 1, j + 2, ... which means starting at index i, with length 0, length 1, length 2 ...... Thats a total of O(n ^ 2) since we memoize and don\'t repeat the calls . Now for each such recursive call, we make at most k more recursive calls. If you draw recursion tree, you will see that, giving us complexity of O(n * n * k)\nHence totalling to O(n * n * k)\n\nNow repeat the step 1 and step 2 above in bottom up DP.  \nNow whatever we did in the above recursive function, put exactly in inner for loop below\n\n```\npublic int palindromePartition(String s, int k) {\n\tint[][] paldp = new int[s.length()][s.length()];\n\tint[][] kdp = new int[s.length()][k];\n\tfor(int end = 0; end < s.length(); end++){\n\t\tfor(int c = 0; c < k; c++){\n\t\t\tkdp[end][c] = s.length(); //set to max value\n\t\t}\n\t\tfor(int start = end; start >= 0; start--){\n\t\t   if(s.charAt(start) == s.charAt(end)){\n\t\t\t   if(end - start > 2) paldp[start][end] = paldp[start + 1][end - 1];\n\t\t   }else {\n\t\t\t   if(end - start <= 2) paldp[start][end] = 1;\n\t\t\t   else paldp[start][end] = 1 + paldp[start + 1][end - 1];\n\t\t   } \n\t\t   for(int c = 0; c < k; c++){\n\t\t\t   if(c == 0) kdp[end][c] = paldp[start][end]; //no more cuts can be made, hence change all chars that you can\n\t\t\t   else if(start -1 >= 0) kdp[end][c] = Math.min(kdp[end][c], paldp[start][end] + kdp[start - 1][c - 1]);\n\t\t   }\n\t\t}\n\t}\n\treturn kdp[s.length() - 1][k - 1];\n}\n```\n
[]