20.暴力递归到动态规划(二)
This commit is contained in:
parent
1448357858
commit
ac55070575
|
@ -0,0 +1,144 @@
|
||||||
|
package com.learn.learn.tixi.twentieth;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
// https://leetcode.com/problems/stickers-to-spell-word/
|
||||||
|
public class ArrToString {
|
||||||
|
public static int minStickers1(String[] stickers,String target){
|
||||||
|
int ans = process1(stickers,target);
|
||||||
|
return ans==Integer.MAX_VALUE?-1:ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
所有贴纸stickers,每一张贴纸都有无穷张
|
||||||
|
target
|
||||||
|
最少张数
|
||||||
|
*/
|
||||||
|
private static int process1(String[] stickers, String target) {
|
||||||
|
if (target.length()==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int min = Integer.MAX_VALUE;
|
||||||
|
// 每张贴纸被剪无数次还剩多少
|
||||||
|
for (String first:stickers){
|
||||||
|
String rest = minus(target,first);
|
||||||
|
if (rest.length()!=target.length()){
|
||||||
|
min=Math.min(min,process1(stickers,rest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min+(min == Integer.MAX_VALUE?0:1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String minus(String s1, String s2) {
|
||||||
|
char[] str1 = s1.toCharArray();
|
||||||
|
char[] str2 = s2.toCharArray();
|
||||||
|
int[] count = new int[26];
|
||||||
|
for (char cha:str1){
|
||||||
|
count[cha-'a']++;
|
||||||
|
}
|
||||||
|
for (char cha:str2){
|
||||||
|
count[cha-'a']--;
|
||||||
|
}
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (int i = 0;i<26;i++){
|
||||||
|
if (count[i]>0){
|
||||||
|
for (int j=0;j<count[i];j++){
|
||||||
|
builder.append((char) (i+'a'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
public static int minStickers2(String[] stickers,String target){
|
||||||
|
int n = stickers.length;
|
||||||
|
// 关键优化(用词频表替代贴纸数组)
|
||||||
|
int[][]counts = new int[n][26];
|
||||||
|
for (int i = 0;i<n;i++){
|
||||||
|
char[]str=stickers[i].toCharArray();
|
||||||
|
for (char cha:str){
|
||||||
|
counts[i][cha-'a']++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int ans = process2(counts,target);
|
||||||
|
return ans == Integer.MAX_VALUE?-1:ans;
|
||||||
|
}
|
||||||
|
// stickers[i] 数组,当初i号贴纸的字符统计 int[][] stickers ->所有的贴纸
|
||||||
|
// 每一种贴纸都有无穷张
|
||||||
|
// 返回搞定target的最少张数
|
||||||
|
public static int process2(int[][] stickers,String t){
|
||||||
|
if (t.length()==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char[] target=t.toCharArray();
|
||||||
|
int[] tcounts= new int[26];
|
||||||
|
for (char cha:target){
|
||||||
|
tcounts[cha-'a']++;
|
||||||
|
}
|
||||||
|
int n = stickers.length;
|
||||||
|
int min = Integer.MAX_VALUE;
|
||||||
|
for (int i = 0;i<n;i++){
|
||||||
|
int[] sticker = stickers[i];
|
||||||
|
// 最关键优化(重要剪枝,这一步也很贪心)
|
||||||
|
if (sticker[target[0]-'a']>0){
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (int j=0;j<26;j++){
|
||||||
|
if (tcounts[j]>0){
|
||||||
|
int nums = tcounts[j]-sticker[j];
|
||||||
|
for (int k = 0;k<nums;k++){
|
||||||
|
builder.append((char)(j+'a'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String rest = builder.toString();
|
||||||
|
min = Math.min(min,process2(stickers,rest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min + (min == Integer.MAX_VALUE?0:1);
|
||||||
|
}
|
||||||
|
public static int minStickers3(String [] stickers,String target){
|
||||||
|
int n=stickers.length;
|
||||||
|
int[][] counts = new int[n][26];
|
||||||
|
for (int i = 0;i<n;i++){
|
||||||
|
char[] str = stickers[i].toCharArray();
|
||||||
|
for (char cha:str){
|
||||||
|
counts[i][cha-'a']++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HashMap<String,Integer> dp = new HashMap<>();
|
||||||
|
dp.put("",0);
|
||||||
|
int ans = process3(counts,target,dp);
|
||||||
|
return ans == Integer.MAX_VALUE?-1:ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int process3(int[][] stickers, String t, HashMap<String, Integer> dp) {
|
||||||
|
if (dp.containsKey(t)){
|
||||||
|
return dp.get(t);
|
||||||
|
}
|
||||||
|
char[] target = t.toCharArray();
|
||||||
|
int[] tcounts = new int[26];
|
||||||
|
for (char cha:target){
|
||||||
|
tcounts[cha-'a']++;
|
||||||
|
}
|
||||||
|
int n=stickers.length;
|
||||||
|
int min = Integer.MAX_VALUE;
|
||||||
|
for (int i=0;i<n;i++){
|
||||||
|
int[] sticker = stickers[i];
|
||||||
|
if (sticker[target[0]-'a']>0){
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (int j= 0 ;j<26;j++){
|
||||||
|
if (tcounts[j]>0){
|
||||||
|
int nums= tcounts[j]-sticker[j];
|
||||||
|
for (int k=0;k<nums;k++){
|
||||||
|
builder.append((char)(j+'a'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String rest = builder.toString();
|
||||||
|
min = Math.min(min,process3(stickers,rest,dp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int ans = min+(min==Integer.MAX_VALUE?0:1);
|
||||||
|
dp.put(t,ans);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.learn.learn.tixi.twentieth;
|
||||||
|
|
||||||
|
public class BagMaxValue {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int [] weight = {3,2,4,7,3,1,7};
|
||||||
|
int [] value = {5,6,3,19,12,4,2};
|
||||||
|
int bag = 15;
|
||||||
|
System.out.println(maxValue(weight,value,bag));
|
||||||
|
System.out.println(dp(weight,value,bag));
|
||||||
|
}
|
||||||
|
//====================================暴力递归
|
||||||
|
public static int maxValue(int[] w,int[] v,int bag){
|
||||||
|
if (w==null||w.length==0||v==null||v.length==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return process(w,v,0,bag);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
要与不要都测试
|
||||||
|
*/
|
||||||
|
public static int process(int[] w,int[] v,int index,int bag){
|
||||||
|
if (bag<0){
|
||||||
|
// 设置无效解
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (index == w.length-1){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// 有货,bag有空间
|
||||||
|
// 不要当前货
|
||||||
|
int p1 = process(w,v,index+1,bag);
|
||||||
|
int next = process(w, v, index + 1, bag - w[index]);
|
||||||
|
int p2 =0 ;
|
||||||
|
if (next!=-1){
|
||||||
|
p2 = v[index]+next;
|
||||||
|
}
|
||||||
|
return Math.max(p1,p2);
|
||||||
|
|
||||||
|
}
|
||||||
|
//========================================缓存
|
||||||
|
// 尝试策略就是动态规划转移方程。
|
||||||
|
// 动态规划转移方程就是尝试策略。
|
||||||
|
public static int dp(int[] w,int[] v,int bag){
|
||||||
|
if (w==null||w.length==0||v==null||v.length==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int n = w.length;
|
||||||
|
int [][] dp = new int[n+1][bag+1];
|
||||||
|
for (int index = n-1;index>=0;index--){
|
||||||
|
for (int rest = 0;rest<=bag;rest++){
|
||||||
|
int p1 = dp[index+1][rest];
|
||||||
|
int p2=0;
|
||||||
|
int next = rest-w[index]<0?-1:dp[index+1][rest-w[index]];
|
||||||
|
if (next!=-1){
|
||||||
|
p2 = v[index]+next;
|
||||||
|
}
|
||||||
|
dp[index][rest]=Math.max(p1,p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[0][bag];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.learn.learn.tixi.twentieth;
|
||||||
|
// https://leetcode.cn/problems/longest-common-subsequence/
|
||||||
|
public class LongestCommonSubsequence {
|
||||||
|
|
||||||
|
public static int longestCommonSubsequence(String s1,String s2){
|
||||||
|
if (s1==null||s2==null||s1.length()==0||s2.length()==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char[] str1 = s1.toCharArray();
|
||||||
|
char[] str2 = s2.toCharArray();
|
||||||
|
return process1(str1,str2,str1.length-1,str2.length-1);
|
||||||
|
}
|
||||||
|
public static int process1(char[] str1,char[] str2,int i,int j){
|
||||||
|
if (i==0&&j==0){
|
||||||
|
return str1[i]==str2[j]?1:0;
|
||||||
|
}else if (i==0){
|
||||||
|
if (str2[j]==str1[i]){
|
||||||
|
return 1;
|
||||||
|
}else {
|
||||||
|
process1(str1,str2,i,j-1);
|
||||||
|
}
|
||||||
|
}else if (j==0){
|
||||||
|
if (str2[j]==str1[i]){
|
||||||
|
return 1;
|
||||||
|
}else {
|
||||||
|
process1(str1,str2,i-1,j);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
// 样本对应,结尾该如何组织可能性
|
||||||
|
// 不以i结尾可能以j结尾,
|
||||||
|
int p1 = process1(str1,str2,i-1,j);
|
||||||
|
// 即以i结尾也不以j结尾,
|
||||||
|
int p2 = process1(str1,str2,i,j-1);
|
||||||
|
// 即以i结尾又以j结尾
|
||||||
|
int p3 = str1[i]==str2[j]?(1+process1(str1,str2,i-1,j-1)):0;
|
||||||
|
return Math.max(p1,Math.max(p2,p3));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int longestCommonSubsequence2(String s1,String s2){
|
||||||
|
if (s1==null||s2==null||s1.length()==0||s2.length()==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char[] str1 = s1.toCharArray();
|
||||||
|
char[] str2 = s2.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 j=1;j<m;j++){
|
||||||
|
dp[0][j]=str1[0]==str2[j]?1:dp[0][j-1];
|
||||||
|
}
|
||||||
|
for (int i=1;i<n;i++){
|
||||||
|
dp[i][0]=str1[i]==str2[0]?1:dp[i-1][0];
|
||||||
|
}
|
||||||
|
for (int i=1;i<n;i++){
|
||||||
|
for (int j=1;j<m;j++){
|
||||||
|
int p1 = dp[i-1][j];
|
||||||
|
// 即以i结尾也不以j结尾,
|
||||||
|
int p2 = dp[i][j-1];
|
||||||
|
// 即以i结尾又以j结尾
|
||||||
|
int p3 = str1[i]==str2[j]?(1+dp[i-1][j-1]):0;
|
||||||
|
dp[i][j]= Math.max(p1,Math.max(p2,p3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[n-1][m-1];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.learn.learn.tixi.twentieth;
|
||||||
|
|
||||||
|
import org.apache.tomcat.util.buf.StringUtils;
|
||||||
|
|
||||||
|
public class NumberConvert {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println(number("111"));
|
||||||
|
System.out.println(dp("111"));
|
||||||
|
System.out.println(number("305"));
|
||||||
|
System.out.println(dp("305"));
|
||||||
|
}
|
||||||
|
public static int number(String str){
|
||||||
|
if (str==null||str.length()==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return process(str.toCharArray(),0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
从0开始看有多少中转换方式
|
||||||
|
*/
|
||||||
|
private static int process(char[] str, int i) {
|
||||||
|
if (i==str.length){
|
||||||
|
// 之前的转换方式
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (str[i]=='0'){//之前决定有问题
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// i 位置单转
|
||||||
|
int ways = process(str,i+1);
|
||||||
|
if(i+1<str.length&&(str[i]-'0')*10+str[i+1]-'0'<27){
|
||||||
|
ways +=process(str,i+2);
|
||||||
|
}
|
||||||
|
return ways;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===================================缓存
|
||||||
|
public static int dp(String str){
|
||||||
|
if (str==null||str.length()==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char[] strChar = str.toCharArray();
|
||||||
|
int n = strChar.length;
|
||||||
|
int[] dp = new int[n+1];
|
||||||
|
// 依赖后面的位置,从右往左填写
|
||||||
|
dp[n]=1;
|
||||||
|
for (int i=n-1;i>=0;i--){
|
||||||
|
if (strChar[i]!='0'){
|
||||||
|
int ways=dp[i+1];
|
||||||
|
if (i + 1 < strChar.length &&(strChar[i]-'0')*10+strChar[i+1]-'0'<27) {
|
||||||
|
ways+=dp[i+2];
|
||||||
|
}
|
||||||
|
dp[i]=ways;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
### 背包问题
|
||||||
|
重量数组w[]
|
||||||
|
价值数据v[]
|
||||||
|
bag maxvalue int
|
||||||
|
自由挑选货物,让背包里装的货物最多
|
||||||
|
|
||||||
|
### 数字对应
|
||||||
|
规定1对应A,2对应B,3对应C,·····,26对应Z,
|
||||||
|
那么一个数字字符串比如‘111’就可以转换为‘AAA’,‘KA’和‘AK’
|
||||||
|
给定一个只有数字字符串组成的字符串str,返回对少中转换结果
|
||||||
|
### 数组转字符串
|
||||||
|
给定一个字符串str,给定一个字符串类型的数组arr,
|
||||||
|
出现的字符都是小写英文arr每一个字符串,代表一张贴纸,
|
||||||
|
你可以把当个字符剪开使用,目的是拼出来str来返回需要至少
|
||||||
|
多少贴纸可以完成任务。
|
||||||
|
例子:str="babac",arr={"ba","c","abcd"}
|
||||||
|
至少需要两张贴纸"ba"和"abcd",因为使用这两张贴纸,
|
||||||
|
把每一个字符串单独剪开,含有2个a、2个b、1个c。是可以
|
||||||
|
拼出str的。所以返回2
|
||||||
|
### 最长公共子序列
|
||||||
|
样本对应模型:
|
||||||
|
|
||||||
|
### 模型
|
||||||
|
1. 从左往右尝试
|
||||||
|
2. 范围尝试
|
||||||
|
3. 样本对应模型
|
||||||
|
4. 业务限制模型
|
Loading…
Reference in New Issue