LintCode867、4キーキーボードの問題(dp配列の定義)

タイトル説明

この質問にはleetcodeのメンバーシップが必要なので、lintcodeにアクセスしました。
https://www.lintcode.com/problem/867/

ここに画像の説明を挿入

解決


初めての解決策初めて簡単にできると思ったので、次のコードを書きました。

public class Solution {
    
    
    /**
     * @param N: an integer
     * @return: return an integer
     */
    public int maxA(int N) {
    
    
        // write your code here
        if(N<0) return -1;
        if(N<=3) return N;
        int []dp = new int[N+1];
        dp[0]=0;
        dp[1]=1;
        dp[2]=2;
        dp[3]=3;
        int cache=0;//记录缓冲区的数据量大小
        for(int i=4;i<=N;i++){
    
    
            //要保证最大,
            if(dp[i-3]>=3 && i-3>=3 && dp[i-3]>3*cache){
    
    //是否能按下c-A\c-c\c-v,同时判断按下3次c-V的收益大还是按下3次c-A\c-c\c-v的收益大
                dp[i] = 2*dp[i-3];//全选、复制、黏贴
                cache = dp[i-3];
              //  System.out.println(cache+" --");
            }else if(cache!=0){
    
    
                dp[i] = dp[i-1]+cache;//只剩下一次机会了

            }else{
    
    
                //只能一个一个按
                dp[i] = dp[i-1]+1;
            }
        }
        return dp[N];
	}
}

実際、これは間違っています。前の状態の選択と後者の状態の選択は依存しておらず、最大の選択関係だからです。たとえば、A、A、A、CA、CC、CVを6回押すと、6つのAが得られますが、7回押すと、7回目のCVを直接押すと9つのAが得られます。

しかし、今100回押すことができれば、10回押すと10回押す結果とは異なる場合があります。

2回目は、ブルートフォースクラッキング-再帰

直接思考では不十分なので、最初に再帰的に考える必要があります。力ずくの方法です。

public class Solution {
    
    
    /**
     * @param N: an integer
     * @return: return an integer
     */
    public int maxA(int N) {
    
    
        return findMaxA(N,0,0);
    }
    public int findMaxA(int times,int A_nums,int cacheNums){
    
    
        if(times<=0) return A_nums;
        return Math.max(
            //按下A
            findMaxA(times-1,A_nums+1,cacheNums),
            Math.max(
                    //按下C-V
                    findMaxA(times-1,A_nums+cacheNums,cacheNums),
                    //按下C-A,C-C
                    findMaxA(times-2,A_nums,A_nums)//缓冲区数目直接变为A_nums
                    )

        );

    }
}

ここに画像の説明を挿入
サブ問題が重複しすぎる可能性があるため、結果はタイムアウトになります。この問題のため:

ここで100回押すことができれば、10回押すと10回押す結果とは異なる場合があります。

したがって、メモを使用するときは、再利用を避けるためにトリプルを使用してください。だからここには書きません。

3番目の方法-dp配列
再定義することがわかります:
A:A、A、... Aを押し続ける(Nが比較的小さい場合)。

A、A、…CA、CC、CV、CV、…CV(Nが比較的大きい場合)のいずれかの形式です。

次に、動的再帰のプロセスについて考えます。

  • 変数とは何ですか?キーストロークの数、Aの数
  • dp [i]は、キーをi回押して、ディスプレイAの最大結果を示します。

オプションについて考える:

  • 最後のキーストロークは、Aを押すか、CVを押して直接コピーするか、CA、CC、CVを押すことでした。
    Aを押す場合、最後の状態にAが追加されたことがわかります。つまり、dp [i] = dp [i-1] +1です。

  • CVを押すのはどうですか?CAとCCがその前に表示される必要があることはわかっています。データをバッファーにコピーするには、CVを使用できます。しかし、その場所は不確かです。次に、CVの最も早い開始点を記録する必要があります。次に、この開始点の前の2つの操作はCA、CCである必要があります。この出発点は私の前にしかあり得ないので、私たちは直接暴力を振るう!

次に、2つの選択肢の中で、現在のdp [i]が最大の結果を取得することによって取得されます。

int[]dp = new int[N+1];
dp[0] = 0;
for(int i=1;i<=N;i++){
    
    
	//选择按下A,
	dp[i] = dp[i-1]+1;
	//选择最后一次操作为按下C-V
	for(int j=2;j<i;j++){
    
    //j必然大于2才可能按下c-v,记录C-V的最早的起点
		//这里全选+复制,那么我们得到了 dp(j-2)缓冲区数目,然后连续按下复制键j-i+1次
		dp[i] = Math.max(dp[i],dp[j-2]*(i-j+1));
		//这里就是暴力遍历,假设每个j都是C-V的最早的起点,找到最大值
	}
}

ここに画像の説明を挿入
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_44861675/article/details/115229851