钻石收集者&是7倍数的最长子序列&Zuma

本篇是寒假的第二弹,虽然每天都有练习算法,但是假期的话想要挤出时间写博客还是比较紧张,还有Linux要学;今天就写了一道算法题,剩下的时间拿出来写博客吧!话不多说上成果!!!

(1)钻石收集者

以以前写的代码展开详细描述与解释,并附上题目

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

const int N=5e4+10;
int n,k;
int a[N];
int f[N],g[N];

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    for(int left=1,right=1;right<=n;right++)
    {
        while(a[right]-a[left]>k) left++;
        f[right]=max(f[right-1],right-left+1);
    }
    for(int left=n,right=n;left>=1;left--)
    {
        while(a[right]-a[left]>k) right--;
        g[left]=max(g[left+1],right-left+1);
    }
    int ret=0;
    for(int i=2;i<=n;i++)
    {
        ret=max(ret,f[i-1]+g[i]);
    }
    cout<<ret<<endl;
    return 0;
}

这是一道在洛谷上写的题目,所以使用全局的变量更加方便,根据输入要求,我直接把数组设置的足够大,那么就不用考虑越界的问题

实现本题的逻辑主要在于滑动窗口思想

  • 首先,需要将数组从大到小依次排序起来这样,方便后面遍历数组
  • 数组fN:从左往右统计一次,正向
  • 数组gN:从右往左统计一次,反向(这两个数组是实现滑动窗口思想的底层容器)
  • fright:表示以right为结尾的数段中,所能达到的最大长度
  • gleft:表示以left为开头的数段中,所能达到的最大长度
  • fi-1+gi:表示以i位置分割的左右两部分,左右结合起来能达到的最大长度
  • ret:因为最大长度可能存在任意一个位置,所以需要暴搜,找寻最终的答案

(2)是7倍数的最长子序列

以以前写的代码展开详细描述与解释,并附上题目

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;

int n;
int id[10];

int main()
{
    cin>>n;
    memset(id,-1,sizeof id);
    id[0]=0;
    int sum=0,ret=0;
    for(int i=1;i<=n;i++)
    {
        int x;cin>>x;
        sum=(sum+x)%7;
        if(id[sum]!=-1) ret=max(ret,i-id[sum]);
        else id[sum]=i;
    }
    cout<<ret<<endl;
    return 0;
}

这是一道在洛谷上写的题目,所以使用全局的变量更加方便,根据输入要求,我直接把数组设置的足够大,那么就不用考虑越界的问题

实现本题的逻辑主要在于前缀和+哈希表+同余定理

  • 数组id:本道题使用数组代替哈希表,这样可以节省空间,因为任意一个数%7后,数值都在0~6之间,所以我们数组不用开太大,就开10即可
  • 初始化:一开始把数组都初始化为-1,这样就可以清楚这个位置我们是否已经遍历过与否,此处值仍为-1,就是还没有遍历过;不为-1,就是已经存进去了一个结点下标

我们需要特地将id0这个点初始化为0,因为如若整个序列就是7的倍数的话,那么计算 的时候,就是拿此时id0内的下标进行计算

  • 实现逻辑:因为是要找到最长的子序列,那么我们只要存%7的0~6这几个数第一次出现的下标即可;后续若重复出现,就可以计算此时的长度,与ret比较
  • 同余定理:文字不方便描述,可以到绑定的资源内看图解,更好理解

(3)Zuma

以今天写的代码展开详细描述与解释,并附上题目

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;

const int N=521;
int n;
int a[N];
int f[N][N];

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    memset(f,0x3f,sizeof f);
    for(int i=1;i<=n;i++)
        f[i][i]=1;
    for(int i=1;i+1<=n;i++)
    {
        int j=i+1;
        if(a[i]==a[j]) f[i][j]=1;
        else f[i][j]=2;
    }

    for(int len=3;len<=n;len++)
    {
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            for(int k=i;k<j;k++)
            {
                //[i,k][k+1][j]
                f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
            }
            if(a[i]==a[j]) f[i][j]=min(f[i][j],f[i+1][j-1]);
        }
    }
    cout<<f[1][n]<<endl;
    return 0;
}

这是一道在洛谷上写的题目,所以使用全局的变量更加方便,根据输入要求,我直接把数组设置的足够大,那么就不用考虑越界的问题

实现本题的逻辑主要在于区间dp

  • 状态表示fij:把区间i,j内的宝石全部移走,所需要的最少步骤
  • 状态表示:

①基于分割点k考虑:fik+fk+1j

②基于左右端点考虑:当ai==aj时,fi+1j-1(容易遗漏,则会错过最优解)

  • 本题难点初始化:

①先将所有的位置初始化为无穷大

②再把所有的基础长度为1,2的区间初始化

③注意fij初始化时,因为会用到fi+1j-1初始化,但是如若不进行第二部,那么两个位置都是无穷大,就无法取出最小值,进行后续的dp(详情可以去绑定的资源内看图解)

相关推荐
祖力552 小时前
数据结构的基本概念与单向链表(链表数据类型构造、创建、头插、尾插、头删、尾删)
数据结构·链表
大明者省3 小时前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
白狐_7985 小时前
408数据结构第8章:排序②——性质对比秒杀、场景选择与外部排序
java·数据结构·算法
zander2585 小时前
LeetCode 84:柱状图中的最大矩形——单调栈如何确定左右边界
java·数据结构·算法
Shell运维手记6 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
杨航 AI6 小时前
O(n log n):线性对数原理拆解 这个是排序算法的黄金复杂度之一。
算法·排序算法
船厂电气自动化ai大模型7 小时前
AI大模型与数学 第32课 函数凹凸性与二阶导数:拐点求解、凹凸区间计算(10道二阶导数计算题)
数据结构·人工智能·python·深度学习·算法
旖旎夜光7 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
叠层归一研究院8 小时前
AGI 系统(十一):二阶网络 — 二阶递归 × 多主体 (元符号网络)
开发语言·人工智能·算法·php·agi
zlinear数据采集卡9 小时前
D223的PWM电机控制:6路独立脉冲+加减速算法深度解析
arm开发·stm32·嵌入式硬件·算法·fpga开发·架构