zoukankan      html  css  js  c++  java
  • leetcode周赛部分代码 动态规划 前缀和

    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;
    }
    

      

    4  题目---------------------------------------------------------------------

    /*

    给你一个整数数组,返回它的某个 非空 子数组(连续元素)在执行一次可选的删除操作后,所能得到的最大元素总和。

    换句话说,你可以从原数组中选出一个子数组,并可以决定要不要从中删除一个元素(只能删一次哦),(删除后)子数组中至少应当有一个元素,然后该子数组(剩下)的元素总和是所有子数组之中最大的。

    注意,删除一个元素后,子数组 不能为空。

    请看示例:

    示例 1:

    输入:arr = [1,-2,0,3]
    输出:4
    解释:我们可以选出 [1, -2, 0, 3],然后删掉 -2,这样得到 [1, 0, 3],和最大。
    示例 2:

    输入:arr = [1,-2,-2,3]
    输出:3
    解释:我们直接选出 [3],这就是最大和。
    示例 3:

    输入:arr = [-1,-1,-1,-1]
    输出:-1
    解释:最后得到的子数组不能为空,所以我们不能选择 [-1] 并从中删去 -1 来得到 0。
    我们应该直接选择 [-1],或者选择 [-1, -1] 再从中删去一个 -1。

    */

    // 解题思路---------------------------------------------------------------------
    int maximumSum(vector<int>& arr) {
    	int len = arr.size();
    	int _max = -100001;
    	int _min = 100001;
    	int sum = 0;
    	//处理特殊情况
    	for (int i = 0;i < len;++i)
    	{
    		if (arr[i] > _max)
    			_max = arr[i];
    		if (arr[i] < _min)
    			_min = arr[i];
    		sum += arr[i];
    	}
    	//如果全是负数返回最大值
    	if (_max <= 0)
    		return _max;
    	//如果全是正数返回总和
    	if (_min >= 0)
    		return sum;
    	sum = 0;
    	//动态规划数组  第一维表示前i位置最大和,第二维是0的时候表示未删除元素,是1的时候代表已经删除了元素
    	int dp[len + 1][2];
    	memset(dp, 0, sizeof(dp));
    	for (int i = 1;i <= len;++i)
    	{
    		//arr[i - 1]代表第i个元素的值
    
    		//没删除元素 类似求最大子数组
    		dp[i][0] = max(arr[i - 1], arr[i - 1] + dp[i - 1][0]);
    
    		//有删除元素,那么删除i就是dp[i][1]=dp[i-1][0]   不删除i那么就是dp[i][1]=dp[i - 1][1] + arr[i - 1]
    		dp[i][1] = max(dp[i - 1][1] + arr[i - 1], dp[i - 1][0]);
    
    		//不断求最大值
    		sum = max(sum, max(dp[i][0], dp[i][1]));
    	}
    
    	return sum;
    }
    

      



  • 相关阅读:
    hadoop上的C++程序开发
    some phrase for oral english
    python的安装,IDLE基本操作
    of这个变态
    一分钟先生: 程序员面试真经
    Cloud Tool 小探索
    【学习总结】数学-欧拉函数
    第三篇——第二部分——第一文 SQL Server镜像简单介绍
    NYOJ 915 +-字符串
    人类主动探索地外文明(METI)活动正在进行中
  • 原文地址:https://www.cnblogs.com/yangshengjing/p/11695807.html
Copyright © 2011-2022 走看看