秋招突击——6/26~6/27——复习{二维背包问题——宠物小精灵之收服}——新作{串联所有单词的字串}

文章目录

引言

  • 今天应该是舟车劳顿的一天,头一次在机场刷题,不学习新的东西了,就复习一些之前学习的算法了。

复习

二维背包问题------宠物小精灵之收服

以往的分析链接


个人实现
  • 这是第二次在做这道题,这是一个单纯的二维背包问题,需要理清楚最后是要你输出什么类型,先给20分钟在开发网站上尝试一下,然后在来具体分析。
c 复制代码
#include <iostream>
#include <cstring>
#include <limits.h>

using namespace std;

const int N = 1010,M = 550,K = 110;// 其中的N表示的精灵球的数量,M是体力值,K是野生精灵的数量

int nt[K],mt[K];
int f[K][N][M];

int n,m,k;

int main(){
    cin>>n>>m>>k;
    for(int i = 1;i <= k;i ++){
        cin>>nt[i]>>mt[i];
    }

    // 二维背包问题计算状态转移矩阵变化的
    int res = f[k][n][m-1];
    for(int i = 1;i <= k;i ++){
        // 针对第i个物体,只有判定抓或者不抓两种情况
        for(int j = 0;j <= n;j ++){
            // 遍历合法情况下的精灵球数量
            for(int l = 0 ;l <= m - 1;l ++){
                // 遍历合法情况下的体力值,注意上下确界,体力值不能消耗完

                // 两种情况,抓或者是不抓,对应需要处理边界值的情况
                if (j-nt[i] >= 0 && l-mt[i] >= 0)
                    f[i][j][l] = max(f[i-1][j][l],f[i-1][j-nt[i]][l-mt[i]] + 1);
                else
                    f[i][j][l] = f[i-1][j][l];
                res = max(f[i][j][l],res);
            }
        }
    }
    cout<<res<<" ";

    // 第二个维度进行判定
    for(int i = 1;i <= k;i ++) {
        // 针对第i个物体,只有判定抓或者不抓两种情况
        for (int j = 1; j <= n; j++) {
            // 遍历合法情况下的精灵球数量
            for (int l = 1; l <= m - 1; l++) {
                if (f[i][j][l] == 2)
                    cout<<"("<<i<<","<<j<<","<<l<<"): "<<f[i][j][l]<<" "<<endl;
            }
        }
    }

    int cost_health = m;
    for(int i = 0;i < m;i ++){
        if(f[k][n][i] == res)
            cost_health = min(cost_health,i);
    }
    cout<<m - cost_health;
}
重大问题
  • 这里有一个重要的发现,就是就是如果使用原始的,不加滚动数组优化的,就得保证每一层之间都能够将信息传递下来,不能因为不满足条件,就直接跳过。
    • 这个bug看了好久,才发现,中间是断层的,之前的决策信息是没有传递下来的,所以最后一行都是空的。
滚动数组优化实现
  • 这里可以使用滚动数组进行优化实现,因为每一次都是从前往后遍历,然后用的是之前的数据。如果使用从后往前遍历,就不需要修改上一个数组了,这里讲的有点模糊,有点混乱。这里直接看我之前的分析吧,具体如下
  • 背包模板------采药问题
  • 设计公式推导,不过不重要,很好记:完全背包问题------买书
  • 这个是公式推导的第二部分:完全背包问题------买书2

最终实现代码如下

  • 实现起来真简单,不得不说,确实厉害!
c 复制代码
#include <iostream>
#include <cstring>
#include <limits.h>

using namespace std;

const int N = 1010,M = 550,K = 110;// 其中的N表示的精灵球的数量,M是体力值,K是野生精灵的数量

int nt[K],mt[K];
int f[N][M];

int n,m,k;

int main(){
    cin>>n>>m>>k;
    for(int i = 1;i <= k;i ++){
        cin>>nt[i]>>mt[i];
    }
    // 二维背包问题计算状态转移矩阵变化的
    for(int i = 1;i <= k;i ++){
        // 针对第i个物体,只有判定抓或者不抓两种情况
        for(int j = n;j >= nt[i];j --){
            // 遍历合法情况下的精灵球数量
            for(int l = m - 1 ;l >= mt[i];l --){
                f[j][l] = max(f[j][l],f[j-nt[i]][l-mt[i]] + 1);
            }
        }
    }
    int res = f[n][m-1];
    cout<<res<<" ";


    int cost_health = m;
    for(int i = 0;i < m;i ++){
        if(f[n][i] == res)
            cost_health = min(cost_health,i);
    }
    cout<<m - cost_health;
}

新作

串联所有单词的字串

  • 题目链接

  • 这题跳了好几次,后面好几题都做了,终于是他了,两天做这道题。

重点

  • words是由若干个子字符串构成的,然后可以按照任意顺序进行拼接,形成n!个字符串,数量很大
  • 每一个字符字串进行匹配查找拼接,这又是一个问题的。每个都是n平方的时间复杂度,根本做不了的。n平方 * n!,这个时间复杂度太高了。根本实现不了的!
  • 可以在以下几个地方做出精简
    • 扫描一次,然后记录所有相同长度,但是起点不同但是长度相同的字符串,然后在按照集合进行比较?这样确实能够缩减时间复杂度。
    • 尝试使用不同的字符串进行优化?最长公共字串有用吗?KMP算法?不得行!
  • 这样吧,匹配出每一个字符串在源字符串的位置,然后将源字符串标注为不同的序列,直接返回对应的序列即可。但是这里有一个问题的,就是这几个 word之间会出现嵌套的问题吗?如果出现嵌套问题就不好做了。
个人实现
  • 字符串s重点长度为x的s.size() - x个子串中,和words中的每一个字符串进行匹配,然后进行标注。判定当前的字符串是相等的,过滤一遍的。记录一下,每一个元素开始的位置,然后再向后进行遍历,保证结果相同?
  • 没有办法保证word和word之间是没有重叠的,这种情况肯定会出现,这就不知道怎么处理了。
  • 不想做了,今天好烦躁呀,还是直接看解说吧。
参考实现
  • 这里参考的y总的代码,基本思路还是很简答的,关键是如何将问题进行拆解,和我的思路比较像,但是有两个地方没有想到

    • 字符串的快速匹配可以使用hash实现,这里我并没有考虑到,在我的设想里面只能使用遍历实现
    • 两个字符字串的匹配使用两个hash表配合滑动窗口实现的
  • 具体思路分析图如下

具体实现代码如下

c 复制代码
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

vector<int> findSubstring(string s,vector<string >& words){
    vector<int> res;
    // 边界条件判定为空
    if (words.empty())  return res;
    // 定义words的长度和word的长度,以及整个string的长度
    int n = s.size(),m = words.size(),w = words[0].size();

    // 定义目标子串中的对应的hash表
    unordered_map<string,int> tot;
    for (auto s:words)  tot[s] ++;

    // 将待匹配的原始的字符串进行等距分割拼接
    for (int i = 0; i < w; ++i) {
        // 定义count记录当前起点下的有效的字符子串的个数
        int cnt = 0;
        // 对每一个起点创建对应的字典字符串
        unordered_map<string,int> temp;
        for (int j = i; j < n; j += w) {
            // 如果长度大于滑动窗口的长度,需要弹出
            if (j >= i + m * w){
                // 已经超过了长度,需要弹出最初的元素
                auto st = s.substr(j - m * w,w);
                temp[st] --;
                // 判定弹出的元素是否有效
                if (temp[st] < tot[st])    cnt--;
            }
            // 需要往队列中添加元素
            auto st = s.substr(j ,w);
            temp[st] ++;
            // 判定加入的元素是否有效
            if (temp[st] <= tot[st])    cnt ++;
            if (cnt == m)   res.push_back(j - (m - 1)*w );
        }
    }

    return res;
}


int main(){

}

总结

  • 刚到上海,总是有很多东西需要收拾,本来准备来实习的,结果的主管面还是把我拒了,确实没有准备好呀,难受,现在就是单纯来学习的了。心里怅然若失!不过无所谓了,先做着吧,尽力去做着吧。来了弄了蛮多家务的,昨天的都没有交稿,脱了两天,明天开始进入状态了,调整一下,不能浪费时间!继续卷吧!然后开始继续弄的!

  • 今天挫败感还是满足的,感觉坐立不安,怎么都不舒服。

    • 换环境了?
    • 没找到实习
  • 都有吧,好好干吧!

相关推荐
浅念同学3 小时前
算法-常见数据结构设计
java·数据结构·算法
UndefindX3 小时前
PAT甲级1006 :Sign In and Sign Out
数据结构·算法
T风呤6 小时前
学生管理系统(通过顺序表,获取连续堆区空间实现)
算法
stackY、6 小时前
【Linux】:程序地址空间
linux·算法
心死翼未伤7 小时前
【MySQL基础篇】多表查询
android·数据结构·数据库·mysql·算法
Orion嵌入式随想录7 小时前
算法训练 | 图论Part1 | 98.所有可达路径
算法·深度优先·图论
西西,正在减肥7 小时前
【leetcode52-55图论、56-63回溯】
算法
Beast Cheng7 小时前
07-7.1.1 查找的基本概念
数据结构·笔记·考研·算法·学习方法
DogDaoDao7 小时前
LeetCode 算法:二叉树中的最大路径和 c++
c++·算法·leetcode·二叉树·二叉树路径
望舒_2338 小时前
【算法专题】双指针算法
算法