钻石收集者&是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(详情可以去绑定的资源内看图解)

相关推荐
写代码写到手抽筋6 小时前
5G上行DCI字段判定:端口 流数 PMI选择详解
java·算法·5g
xieliyu.6 小时前
Java算法精讲:双指针(二)
java·开发语言·算法
wayz117 小时前
Momentum:PSL(心理线指标)技术指标详解
算法·金融·数据分析·量化交易·特征工程
8Qi88 小时前
LeetCode 213:打家劫舍 II(House Robber II)—— 题解 ✅
算法·leetcode·职场和发展·动态规划
三品吉他手会点灯8 小时前
C语言学习笔记 - 44.运算符和表达式 - 运算符2 - 除法与取余运算符
c语言·开发语言·笔记·算法
乐迪信息8 小时前
乐迪信息:AI算法盒子实时识别船舶烟雾与火焰异常
大数据·人工智能·算法·安全·目标跟踪
J-Tony118 小时前
【JVM】根可达算法
jvm·算法
艾iYYY8 小时前
string 类的模拟实现
android·服务器·c语言·c++·算法
Lsk_Smion9 小时前
力扣实训 _ [75].颜色分类 _ 杨辉三角
数据结构·算法·leetcode