天池在线编程 2020年9月26日 日常周赛题解

题目地址,请点这

1. K步编辑

给出一个只含有小写字母的字符串的集合以及一个目标串(target),输出所有可以经过不多于 k 次操作得到目标字符串的字符串。

你可以对字符串进行一下的3种操作:

  • 加入1个字母
  • 删除1个字母
  • 替换1个字母

考查动态规划:最短编辑距离

class Solution {
public:
    /**
     * @param words: a set of stirngs
     * @param target: a target string
     * @param k: An integer
     * @return: output all the strings that meet the requirements
     */
    vector<string> kDistance(vector<string> &words, string &target, int k) {
        // write your code here
        vector<string> ans;
        for(auto& w : words)
        {
            if(minDistance(w, target) <= k)
                ans.push_back(w);
        }
        return ans;
    }
    int minDistance(string word1, string word2) {
        int n1 = word1.size(), n2 = word2.size(), i, j;
        if(n1==0 || n2==0) 
            return max(n1,n2);
        int dp[n1+1][n2+1];

        for(i = 0; i < n1+1; i++)
            dp[i][0] = i;
        for(j = 0; j < n2+1; j++)
            dp[0][j] = j;

        // DP
        int left, up, left_up;
        for(i = 1; i < n1+1; i++) 
        {
            for(j = 1; j < n2+1; j++) 
            {
                left    = dp[i-1][j];
                up      = dp[i][j-1];
                left_up = dp[i-1][j-1];
                if(word1[i-1] != word2[j-1]) 
                    dp[i][j] = 1 + min(left, min(up, left_up));
                else// word1[i-1] == word2[j-1]
                    dp[i][j] = left_up;
            }
        }
        return dp[n1][n2];
    }
};

2. 折纸

折纸,每次都是将纸从右向左对折,凹痕为 0,凸痕为 1,求折 n 次后,将纸展开所得折痕组成的 01 序列。
1 < = n < = 20 1<=n<=20 1<=n<=20

  • 找规律,拿张纸,折几次就会发现规律了。下一个序列是在前一个序列的基础上插空加入010101...
class Solution {
public:
    /**
     * @param n: The folding times
     * @return: the 01 string
     */
    string getString(int n) {
        // Write your code here
        if(n==1) return "0";
        string ans, temp = "0";
        while(--n)
        {
            int flag = 0;
            for(int i = 0; i < temp.size(); i++)
            {
                ans += string(1, flag+'0')+temp[i];
                flag = (flag==0 ? 1 : 0);
            }
            ans += "1";
            temp = ans;
            ans = "";
        }
        return temp;
    }
};

3. 字符串的不同排列

给出一个字符串,找到它的所有排列,注意同一个字符串不要打印两次。 请以字典序从小到大输出。 0<=n<=20

排列组合,回溯+剪枝

class Solution {
public:
    /**
     * @param str: A string
     * @return: all permutations
     */
    vector<string> ans;
    vector<string> stringPermutation(string &str) {
        // write your code here
        sort(str.begin(), str.end());
        vector<bool> vis(str.size(), false);
        string s;
        dfs(str, s, 0, vis);
        return ans;
    }
    void dfs(string &str, string &s, int idx, vector<bool> &vis)
    {
        if(idx == str.size())
        {
            ans.push_back(s);
            return;
        }
        for(int i = 0; i < str.size(); i++)
        {
            if(vis[i])
                continue;
            if(i >= 1 && !vis[i-1] && str[i-1] == str[i])
                continue;//剪枝,去重
            s += str[i];
            vis[i] = true;
            dfs(str, s, idx+1, vis);
            vis[i] = false;
            s.pop_back();
        }
    }
};

4. 硬币排成线

有 n 个硬币排成一条线, 第 i 枚硬币的价值为 values[i].

两个参赛者轮流从任意一边取一枚硬币, 直到没有硬币为止. 拿到硬币总价值更高的获胜.

请判定 第一个玩家 会赢还是会输. 1 < = n < = 2000 1<=n<=2000 1<=n<=2000

  • 博弈 动态规划,dp[i][j] 表示剩余硬币为 [i,j] 时,我跟对手的最大差值
class Solution {
public:
    /**
     * @param values: a vector of integers
     * @return: a boolean which equals to true if the first player will win
     */
    bool firstWillWin(vector<int> &values) {
        // write your code here
        int n = values.size(), i, j;
    	vector<vector<int>> dp(n, vector<int>(n, INT_MIN));
    	for(i = 0; i < n; ++i)
    		dp[i][i] = values[i];
    	for(int len = 1; len < n; ++len)
    	{
    		for(i = 0; i+len < n; ++i)
    		{
    			dp[i][i+len] = max(values[i]-dp[i+1][i+len], values[i+len]-dp[i][i+len-1]);
    		}
    	}
    	return dp[0][n-1] > 0;
    }
};

我的CSDN博客地址 https://michael.blog.csdn.net/

长按或扫码关注我的公众号(Michael阿明),一起加油、一起学习进步!
Michael阿明

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael阿明

如果可以,请点赞留言支持我哦!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值