20.暴力递归到动态规划(二)

This commit is contained in:
huayu 2022-06-26 15:14:29 +08:00
parent 1448357858
commit ac55070575
5 changed files with 363 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -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];
}
}

View File

@ -0,0 +1,27 @@
### 背包问题
重量数组w[]
价值数据v[]
bag maxvalue int
自由挑选货物,让背包里装的货物最多
### 数字对应
规定1对应A2对应B3对应C·····26对应Z
那么一个数字字符串比如111就可以转换为AAAKAAK
给定一个只有数字字符串组成的字符串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. 业务限制模型