LC. 16.11面试题 跳水板(动态规划)

今天刷题遇到一道特别奇葩的题,看起来是用动态规划解,题型分类也是动态规划,但是用动态规划确实TML,而最优解法感觉却有点像“脑筋急转弯”,I fulo U, 还是太菜了。

题目描述

LC. 16.11面试题 跳水板(动态规划)_第1张图片
我的解法:

1. 记忆化(TML)

    vector<int> ans;
    int l, s; 
    set<string> st;
    void dfs(int k, int len)
    {
        string key = to_string(k) + "_" + to_string(len);
        if (st.find(key) != st.end()) return;
        if (k == 0)
        {
            st.insert(key);
            ans.push_back(len);
            return;
        }
        dfs(k - 1, len + l);
        dfs(k - 1, len + s);
        st.insert(key);
    }
    vector<int> divingBoard(int shorter, int longer, int k) {
        if(k == 0) return {};
        if(shorter == longer) return {k * longer};
        l = longer;
        s = shorter;
        dfs(k, 0);
        sort(ans.begin(), ans.end());
        return ans;
    }

3. 动态规划(TML)

    vector<int> divingBoard(int shorter, int longer, int k) {
        if(k <= 0) return {};
        if(longer == shorter) return {k*longer};
        vector<vector<int>> dp(k,vector<int>(k*longer+1,0));
        
        dp[0][shorter] = 1;
        dp[0][longer] = 1;
        
        for(int i = 1; i < k; i++)
        {
            for(int j = 1; j < dp[i].size(); j++)
            {
                if(dp[i-1][j] == 1) 
                {
                    dp[i][j+shorter] = 1;
                    dp[i][j+longer] = 1;
                }
            }
        }
        vector<int> ans;
        for(int i = 0; i < k*longer+1; i++)
        {
            if(dp[k-1][i]) ans.push_back(i);
        }
        return ans;
    }

这里的动态规划有很多无效计算没有优化,因为优化后会发现其实和记忆化是一样的,这里就说下优化的思路吧
在遍历每个i对应的行时,我们可以不用遍历j: 1 ~ dp[i].size(),只记录有用信息的状态,对应题目里就是dp[i][j]=1的信息,我们每次把它包存在一个队列里面,然后遍历就只遍历队列的上个状态的长度,在遍历的过程中此次遍历的结果加入队尾即可。

3. 最优解法

思路:

  • 当两种板子长度相同的时候,显然无论如何组合,跳板的长度均为 k*shorter。故只有一种长度。

  • 当两种板子的长度不相同的时候,可以组合出 k+1 种长度的跳板,证码过程如下:

  • 首先,我们选择k块短板,此时长度为 k*shorter。这是一种方案。

  • 每用一块长板替换掉一块短板,跳板的长度就会增加 longer - shorter。故每替换一次,就会产生一种新方案。一共可以替换k次。故总共有 k + 1 种方案。

    vector<int> divingBoard(int shorter, int longer, int k) {
        if(k <= 0) return {};
        if(shorter == longer) return vector<int>(1,k * shorter);
        vector<int> ans;
        
        for(int i = 0; i <= k; i++)
            ans.push_back((k - i) * shorter + i * longer);
            
        return ans;
    }

这个解法我是看题解才知道的,之前全部时间都去推动态规划去了(哎!大神果然都不一般)。

你可能感兴趣的:(LeetCode)