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