シングル型配列DP
相比一维DP,这种类型状态转移与过去每个阶段的状态都有关。
- 増加部分列最長:最大値と最小要件
- 正方形パーフェクト:スケール値を見つけます
- トリプレットサブシーケンスは増加:需要があるかどうか
- 変更COIN:最大と最小要件
- ブレイク整数:最大と最小要件
- 割り切れサブセット最大:最大値と最小要件
- 合計IVコンビネーション:いくつかの方法を見つけます
パーフェクト正方形:
方法:+再帰メモまで底から
{F(I)+ F(ニッケル)、I = 1の1-N ...} Fは、(N)=分
class Solution {
public int numSquares(int n) {
int[] memo = new int[n];
for(int i = 1; i <= n; i++){
if(i * i <= n){
memo[i*i - 1] = 1;
}
}
if(memo[n-1] == 1) return 1;
memo[1] = 2;
for(int i = 3; i <= n; i++){
if(memo[i-1] == 1) continue;
int left = 1;
int right = i - 1;
int mini = Integer.MAX_VALUE;
while(left <= right){
if(left + right == i){
mini = Math.min(mini, memo[left - 1] + memo[right - 1]);
}
left ++; right--;
}
memo[i-1] = mini;
}
return memo[n - 1];
}
}
方法2:再帰+メモ
さらには、この質問が有する4乗と定理の数を、特定の基準
class Solution {
public int numSquares(int n) {
int[] memo = new int[n + 1];
memo[0] = 0;
for(int i = 1; i <= n; i++){
int mini = Integer.MAX_VALUE;
for(int j = 1; j <= i; j ++){
int t = j*j;
if(t > i) break;
if(t == i) mini = 1;
else mini = Math.min(mini, memo[t] + memo[i-t]);
}
memo[i] = mini;
}
return memo[n];
}
}
最長増加部分列
方法:ボトムアップ、再帰+メモ
この質問は、比較的長い時間のような状態遷移では、与えられた、出て来たくなかったの参照をgrandyang。
参考にも2つの検索方法を使用して、ソリューションのnlog(n)を導入し、 。
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length == 0) return 0;
int[] memo = new int[nums.length];
memo[0] = 1;
int maxi = 1;
for(int i = 1; i < nums.length; i++){
memo[i] = 1;
for(int j = i - 1; j >= 0; j--){
if(nums[i] > nums[j])
memo[i] = Math.max(memo[i], memo[j] + 1);
}
maxi = Math.max(memo[i], maxi);
}
return maxi;
}
}
トリプレットサブシーケンスは増加:需要があるかどうか
方法:再帰+メモボトムアップから
class Solution {
public boolean increasingTriplet(int[] nums) {
if(nums.length == 0) return false;
int[] memo = new int[nums.length];
memo[0] = 1;
boolean exist = false;
for(int i = 1; i < nums.length; i ++){
memo[i] = 1;
for(int j = 0; j < i; j ++){
if(nums[i] > nums[j]){
memo[i] = Math.max(memo[j] + 1, memo[i]);
}
}
if(memo[i] == 3){
exist = true;break;
}
}
return exist;
}
}
コインの変更
方法:ボトムアップ
再帰+メモ
他の型との直接使用は、結果がエラー与えないであろう場合
、DP法を全く最適化、保存+再帰分岐も最適化することができる、参照して
最適化方法を保存分岐され、一般的に使用されるDFS / BFSは、ツリーの探索空間の検索条件によって除外を参照して
class Solution {
public int coinChange(int[] coins, int amount) {
Arrays.sort(coins);
int[] memo = new int[amount + 1];
for(int i = 1; i <= amount; i++){
memo[i] = Integer.MAX_VALUE;
for(int j = coins.length - 1; j >= 0; j--){
if(i < coins[j]) continue;
if(i == coins[j]){
memo[i] = 1;
continue;
}
int m = i - coins[j];//此处若修改为 m = i % coins[j]会出错
if(memo[m] != -1){
memo[i] = Math.min(memo[i], 1 + memo[m]);
}
}
memo[i] = (memo[i] == Integer.MAX_VALUE) ? -1 : memo[i];
}
return memo[amount];
}
}
整数ブレイク
方法:ボトムアップ、再帰+メモ
のようなコインの変更
class Solution {
public int integerBreak(int n) {
int[] memo = new int[n + 1];
memo[0] = 1;
memo[1] = 1;
memo[2] = 1;
for(int i = 3; i <= n; i++){
int a = i / 2 + 1;
for(int j = 1; j < a; j++){
int x = Math.max(j, memo[j]);
int y = Math.max(i - j, memo[i - j]);
memo[i] = Math.max(memo[i], x * y);
}
}
return memo[n];
}
}
最大の可分サブセット
方法:ボトムアップ、再帰+メモ
class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
if(nums.length < 1) return new ArrayList<>();
List<List<Integer>> memo = new ArrayList<List<Integer>>();
Arrays.sort(nums);
int gIdx = 0;
int gLen = 0;
List<Integer> li = new ArrayList<>();
li.add(nums[0]);
memo.add(li); // 1
for(int i = 1; i < nums.length; i ++){
int longIdx = i;
int longLen = 0;
for(int j = 0; j < i; j++){
int tlen = memo.get(j).size();
if(nums[i] % memo.get(j).get(tlen - 1) == 0){
if(longLen < tlen){
longLen = tlen; longIdx = j;
}
}
}
if(longIdx == i){
List<Integer> li2 = new ArrayList<>();
li2.add(nums[i]);
memo.add(li2);
}
else{
List<Integer> li3 = new ArrayList<>(memo.get(longIdx));
li3.add(nums[i]);
memo.add(li3);
if(memo.get(i).size() > gLen){
gIdx = i; gLen = memo.get(i).size();
}
}
}
if(gLen == 0) return memo.get(0);
return memo.get(gIdx);
}
}
コンビネーション合計IV
方法:トップダウンバックトラックTimeLimitExceed、11月17日
class Solution {
public int combinationSum4(int[] nums, int target) {
Arrays.sort(nums);
return dfs(nums, target);
}
int dfs(int[] nums, int tgt){
if(tgt == 0){
return 1;
}
else if(tgt < 0){
return 0;
}
int sumC = 0;
for(int i = 0; i < nums.length; i ++){
int newTgt = tgt - nums[i];
if(newTgt >= 0){
sumC += dfs(nums, newTgt);
}
else{
break;
}
}
return sumC;
}
}
方法2:ボトムアップ再帰+メモ
class Solution {
public int combinationSum4(int[] nums, int target) {
Arrays.sort(nums);
int[] memo = new int[target + 1];
memo[0] = 0;
for(int i = 1; i <= target; i++){
for(int j = 0; j < nums.length; j++){
if(i < nums[j]){
continue;
}
if(i == nums[j]){
memo[i] += 1;
}
else{
int t = i - nums[j];
if(memo[t] != 0){
memo[i] += memo[t];
}
}
}
}
return memo[target];
}
}