首页 > 其他 > 详细

leetcode周赛部分代码 动态规划

时间:2019-10-18 00:00:51      阅读:72      评论:0      收藏:0      [点我收藏+]

1  题目---------------------------------------------------------------------

有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数。

不过我们在使用它时有个约束,就是使得投掷骰子时,连续 掷出数字 i 的次数不能超过 rollMax[i]i 从 1 开始编号)。

现在,给你一个整数数组 rollMax 和一个整数 n,请你来计算掷 n 次骰子可得到的不同点数序列的数量。

假如两个序列中至少存在一个元素不同,就认为这两个序列是不同的。由于答案可能很大,所以请返回 模 10^9 + 7 之后的结果。

例子:

输入:n = 2, rollMax = [1,1,2,2,2,3]
输出:34
解释:我们掷 2 次骰子,如果没有约束的话,共有 6 * 6 = 36 种可能的组合。但是根据 rollMax 数组,数字 1 和 2 最多连续出现一次,所以不会出现序列 (1,1) 和 (2,2)。因此,最终答案是 36-2 = 34。

输入:n = 2, rollMax = [1,1,1,1,1,1]
输出:30
输入:n = 3, rollMax = [1,1,1,2,2,3]
输出:181

// 解题思路---------------------------------------------------------------------
/*
dp[i][j]的值代表第i个骰子,结尾的数字是j的次数  那么我们的结果就是dp[n][1]+dp[n][2]+dp[n][3]+dp[n][4]+dp[n][5]+dp[n][6]

动态转移方程就是  dp[i][j]=∑dp[i-L][k!=j]   其中 1<=L<=rollMax[j-1]  1<=k<=6   连续 掷出数字 j 的次数不能超过 rollMax[j]

_ _ _ _ 2   假如rollMax[j-1]=1 那么倒数第二个位置就不能为2  dp[i][j]+=dp[i-1][k!=j] 
如果rollMax[j-1]=2 倒数第二个位置和倒数第三个位置不能为2  dp[i][j]+=dp[i-1][k!=j]+dp[i-2][k!=j] 

如果rollMax[j-1]大于等于骰子数i 显然不可能扔出这种情况,那么dp[i][j]=∑dp[i-1][k] 
*/

//结果可能非常大,设置取mod常数 
const int P = 1e9 + 7;

int dieSimulator(int n, vector<int>& rollMax) {

	//初始化数组(n不是常量,所以这里不够严谨)
	int dp[n + 1][7]; 
	memset(dp, 0, sizeof(dp)); 
	dp[1][1] = dp[1][2] = dp[1][3] = dp[1][4] = dp[1][5] = dp[1][6] = 1;

	//开始循环
	for (int i = 1;i <= n;++i)                        //第一重 代表骰子数
	{
		for (int j = 1;j <= 6;++j)                  //第二重 代表以j为结尾
		{
			for (int k = 1;k <= 6;++k)              //第三重和第四重 用来求和
			{
				for (int l = 1;l <= rollMax[j - 1];++l)  
				{
					if (rollMax[j - 1] >= i)
					{
						//如果不超过的次数大于骰子数,那么dp[i][j]+=dp[i-1][k] 
						dp[i][j] = (dp[i][j] % P + dp[i - 1][k] % P) % P;
						break;
					}
					else
					{
						//dp[i][j]+=dp[i-1][k]  其中k不等于j
						if (i - l > 0 && k != j)
						{
							dp[i][j] = (dp[i][j] % P + dp[i - l][k] % P) % P;
						}
					}
				}
			}

		}

	}
	return ((((((dp[n][1] % P + dp[n][2] % P) % P + dp[n][3] % P) % P + dp[n][4] % P) % P + dp[n][5] % P) % P + dp[n][6] % P) % P) % P;
}

 

2  题目---------------------------------------------------------------------

给你一个整数数组 arr 和一个整数 difference,请你找出 arr 中所有相邻元素之间的差等于给定 difference 的等差子序列,并返回其中最长的等差子序列的长度。

例子:
输入:arr = [1,2,3,4], difference = 1
输出:4
解释:最长的等差子序列是 [1,2,3,4]。

输入:arr = [1,3,5,7], difference = 1
输出:1
解释:最长的等差子序列是任意单个元素。

输入:arr = [1,5,7,8,5,3,4,2,1], difference = -2
输出:4
解释:最长的等差子序列是 [7,5,3,1]。
  • 1 <= arr.length <= 10^5
  • -10^4 <= arr[i], difference <= 10^4
// 解题思路---------------------------------------------------------------------
int longestSubsequence(vector<int>& arr, int difference) {

	int len = arr.size();
	if (len == 0)
		return 0;
	if (len == 1)
		return 1;

	//动态规划初始化
	int dp[20010] = { 0 };
	dp[0] = 0;

	//保存最大长度
	int temp = -1;
	//先把元素值变为正数
	for (int i = len - 1;i >= 0;--i)
	{
		arr[i] += 10000;
	}
	//状态转移方程  从后往前,dp[arr[i]]=dp[arr[i] + difference]+1  
	for (int i = len - 1;i >= 0;--i)
	{
		//如果数组越界直接置为1 因为该值只能是等差数列边界值
		if (arr[i] + difference < 0 || arr[i] + difference>20000)
		{
			dp[arr[i]] = 1;
			continue;
		}
		
		dp[arr[i]] = dp[arr[i] + difference] + 1;

		//取最大长度
		temp = max(temp, dp[arr[i]]);
	}

	return temp;
}

 3  题目--------------------------------------------------------------------- 

给你两个长度相同的字符串,s 和 t

将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。

用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。

如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。

如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0

例子:

输入:s = "abcd", t = "bcdf", cost = 3
输出:3
解释:s 中的 "abc" 可以变为 "bcd"。开销为 3,所以最大长度为 3。
输入:s = "abcd", t = "cdef", cost = 3
输出:1
解释:s 中的任一字符要想变成 t 中对应的字符,其开销都是 2。因此,最大长度为 1。
输入:s = "abcd", t = "acde", cost = 0
输出:1
解释:你无法作出任何改动,所以最大长度为 1。
  • 1 <= s.length, t.length <= 10^5
  • 0 <= maxCost <= 10^6
  • s 和 t 都只含小写英文字母。
// 解题思路---------------------------------------------------------------------
int equalSubstring(string s, string t, int maxCost) {
	int lens = s.size();
	if (lens == 0)
		return 0;
	//保存每个位置的cost 题目转变成就最长子数组(不需要连续)的和不大于cost
	vector<int>res;
	for (int i = 0;i < lens;++i)
	{
		res.push_back(abs(s[i] - t[i]));
	}
	
	//前缀和数组
	int dp[lens + 1];              //这里可以使用vector
	dp[0] = 0;
	int ans = 0;

	//求以第i个字符为结尾的cost 因为元素都非负数,其实就是前缀和
	for (int i = 1;i <= lens;++i)
	{
		dp[i] = dp[i - 1] + res[i - 1];
	}

	//遍历区间(j,i)的总cost不大于maxCost的情况中的最大距离。						
	for (int i = 1, j = 0;i <= lens;++i)
	{
		//当遍历到第一个dp[i]-dp[0]>maxCost时,j指针从0向前移动,直到dp[i] - dp[j]<= maxCost 
		for (;dp[i] - dp[j] > maxCost;++j);
		ans = max(ans, i - j);
	}
	return ans;
}

  




leetcode周赛部分代码 动态规划

原文:https://www.cnblogs.com/yangshengjing/p/11695807.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!