算法练习2023/4/20

1.方块与收纳盒

          现在有一个大小n*1的收纳盒,我们手里有无数个大小为1*1和2*1的小方块,我们需要用这些方块填满收纳盒,请问我们有多少种不同的方法填满这个收纳盒。

正确代码:

//dp
#include<bits/stdc++.h>
using namespace std;
long dp[100];
int main()
{
    dp[1]=1;
    dp[2]=2;
    for(int i=3;i<100;i++)
        dp[i]=dp[i-2]+dp[i-1];
    int n;
    cin>>n;
    while(n--)
    {
        int a;cin>>a;
        cout<<dp[a]<<endl;
    }
    return 0;
}

总结:这是一道经典的动态规划算法题:

规律: 空间4 由空间3的所有方法(1*1的包)+空间2的所有的方法(1*2的包)。

2.给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
  • 穷举分析
  • 确定边界
  • 找规律,确定最优子结构
  • 状态转移方程

一:

  • 当nums只有一个元素10时,最长递增子序列是[10],长度是1.
  • 当nums需要加入一个元素9时,最长递增子序列是[10]或者[9],长度是1。
  • 当nums再加入一个元素2时,最长递增子序列是[10]或者[9]或者[2],长度是1。
  • 当nums再加入一个元素5时,最长递增子序列是[2,5],长度是2。
  • 当nums再加入一个元素3时,最长递增子序列是[2,5]或者[2,3],长度是2。
  • 当nums再加入一个元素7时,,最长递增子序列是[2,5,7]或者[2,3,7],长度是3。
  • 当nums再加入一个元素101时,最长递增子序列是[2,5,7,101]或者[2,3,7,101],长度是4。
  • 当nums再加入一个元素18时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4。
  • 当nums再加入一个元素7时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4.

二:

        如果新加入一个元素nums[i], 最长递增子序列要么是以nums[i]结尾的递增子序列,要么就是nums[i-1]的最长递增子序列

        (其实,nums[i]结尾的自增子序列,只要找到比nums[i]小的子序列,加上nums[i] 就可以啦。显然,可能形成多种新的子序列,我们选最长那个,就是dp[i]的值。)

三: 

dp(i) =max(dp(j))+1,存在j属于区间[0,i-1],并且num[i]>num[j]。

正确代码:

class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[] dp = new int[nums.length];
        //初始化就是边界情况
        dp[0] = 1;
        int maxans = 1;
        //自底向上遍历
        for (int i = 1; i < nums.length; i++) {
            dp[i] = 1;
            //从下标0到i遍历
            for (int j = 0; j < i; j++) {
                //找到前面比nums[i]小的数nums[j],即有dp[i]= dp[j]+1
                if (nums[j] < nums[i]) {
                    //因为会有多个小于nums[i]的数,也就是会存在多种组合了嘛,我们就取最大放到dp[i]
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            //求出dp[i]后,dp最大那个就是nums的最长递增子序列啦
            maxans = Math.max(maxans, dp[i]);
        }
        return maxans;
    }
}

源引:https://zhuanlan.zhihu.com/p/365698607

3.舔狗舔到最后一无所有

      作为队伍的核心,forever97很受另外两个队友的尊敬。
Trote_w每天都要请forever97吃外卖,但很不幸的是宇宙中心forever97所在的学校周围只有3家forever97爱吃的外卖。
如果Trote_w给forever97买了别家的外卖,forever97就会大喊“我不吃我不吃”。
但是forever97又不喜欢连续三天吃一种外卖。
如果Trote_w哪天忘了这件事并且三天给他买了同一家外卖,那么forever97就会把Trote_w的头摁进手机屏幕里。
作为Trote_w的好朋友,你能告诉他连续请forever97吃n天饭,有多少不同的购买方法吗?

多组样例
第一行一个整数T(1<=T<=20)代表测试样例数
接下来t行每行一个整数n,代表Trote_w要请forever97吃n天饭(1<=n<=100000)
输出T个整数代表方案数,由于答案太大,你只需要输出mod 1e9+7 后的答案即可。

示例1

正确代码:

#include<bits/stdc++.h>
using namespace std;
long long dp[100000];
const int maxt=1e9+7;
int main()
{
	//因为买1餐厅和2,3是一样的,所以只求其中一个,再乘3
	//由题意 如果第i天买了1,则可以加上第i-1买2,3的所有情况 dp[i]+=dp[i-1]*2 
	//如果第i-1也买1,则第i-2一定不能买1   
	// 所以第i-1天买1的情况 - 第i-2天买1的所有情况(即i-3天选2、3,因为以及有两天选1了) 
	//即: dp[i-1]-dp[i-3]*2
	//注意:每一天其实都是经过求模后的结果,所以在关系式中也要求模计算 
	dp[1]=1;
	dp[2]=3;
	dp[3]=8;
	for(int i=4;i<100000;i++)
	{
		dp[i] = ((dp[i-1]*3%maxt-dp[i-3]*2%maxt)+maxt)%maxt;
	}
	int n;
	cin>>n;
	while(n--)
	{
		int a;
		cin>>a;
		printf("%lld\n",dp[a]*3%maxt);
	}
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值