秋招突击——6/22——复习{区间DP——加分二叉树,背包问题——买书}——新作{溢出元素、实现strStr()}

news2024/11/27 6:20:04

文章目录

    • 引言
    • 复习
      • 区间DP——加分二叉树
        • 个人实现
      • 背包问题——买书
        • 个人实现
        • 参考实现
    • 新作
      • 移除元素
        • 个人实现
        • 参考思路
      • 找出字符串中第一个匹配项的下标
        • 个人实现
        • 参考实现
    • 总结

引言

  • 今天做了一个噩梦,然后流了一身汗,然后没起来,九点多才起床背书。十点钟才开始把昨天那道题题目过一遍,然后十一点才开始复习题目,为了不耽误下午的时间,所以这里的就单纯做已经做过的题目,主打一个有量,不在学习新的dp。

复习

区间DP——加分二叉树

  • 这道题差不多看了第二遍,第一次学的时候就蛮难的,不过有固定的编程范式,不过这里没想起来。提供一下之前的分析思路。

    • 第一次分析
    • 区间DP——合并石子
  • 之前做了两次,这次看看能不能一次过。

个人实现
  • 区间DP集合表示是f[i][j],
    • i是区间的左端点
    • j是区间的右端点,
  • 集合划分是区间的中间的,所以需要遍历枚举区间[i,j]中所有的区间分割点
  • 具体的代码流程如下
    • 列举区间长度
    • 列举区间左端点
    • 枚举的区间的分割点

实现问题

  • 区间长度的上下限有没有特殊情况,需不需要特殊考虑?如果区间长度为1,或者为n怎么办?
  • 特殊情况1
    • 区间长度为1,表示的左右子节是重合的,所以需要特殊考虑,当前情况是叶子节点
    • 区间长度就是1到n,不用考虑n+1,之前那个题目使用n+1是特殊情况,实际情况下,不需要使用使用n+1,而且这道题使用n+1也没有任何意义,那道题股票买卖题n+1一天的某种情况,是之前最大的。
#include <iostream>

using namespace std;

const int N = 35;
int f[N][N],n,rp[N][N];  // f表示区间的状态记录,r表示根节点的记录状态
int s[N];

void dfs(int l,int r){
    if (l > r)  return ;
    int k = rp[l][r];
    cout<<k<<" ";
    if (k - 1 >= l) dfs(l,k - 1);
    if (k + 1 <= r) dfs(k + 1,r);
}

int main(){
    cin>>n;
    for (int i = 1; i <= n; ++i) {
        cin>>s[i];
        s[i] += s[i - 1];
    }
    
    // 区间DP
    for (int len = 1; len <= n; ++len) {
        // 列举区间左端点
        for (int l = 1; l + len <= n; ++l) {
            // 计算区间的右端点
            int r = l + len  - 1;
            // 列举区间的分割点
            for (int k = l; k <= r; ++k) {
            	if(看== 1int temp;
                if (k == l){
                    // 左端点为空
                    temp = (s[k] -s[k - 1]) + f[k + 1][r];
                }else if(k == r){
                    // 右子树为空
                    temp = (s[k] -s[k - 1]) + f[l][k - 1];
                }else{
                    // 左右子树都不为空
                    temp = (s[k] -s[k - 1]) + f[k + 1][r] * f[l][k - 1];
                }
                // 比较确定最大值的并进行记录
                if (f[l][r] < temp) {
                    rp[l][r] = k;
                    f[l][r] = temp;
                }
            }
        }
    }
    
    cout<<f[0][n];
    dfs(0,n);
    
    return f[0][n];
    
}

修改之后的如下

  • 其实这里有两个地方还是可以修改的,左右节点的情况是可以特殊讨论和考虑的。
#include <iostream>

using namespace std;

const int N = 35;
int f[N][N],n,rp[N][N];  // f表示区间的状态记录,r表示根节点的记录状态
int s[N];

void dfs(int l,int r){
    if (l > r)  return ;
    int k = rp[l][r];
    cout<<k<<" ";
    if (k - 1 >= l) dfs(l,k - 1);
    if (k + 1 <= r) dfs(k + 1,r);
}

int main(){
    cin>>n;
    for (int i = 1; i <= n; ++i) {
        cin>>s[i];
    }
    
    // 区间DP
    for (int len = 1; len <= n; ++len) {
        // 列举区间左端点
        for (int l = 1; l + len <= n; ++l) {
            // 计算区间的右端点
            int r = l + len  - 1;
            if (l == r) f[l][r] = s[l],rp[l][r] = l;
            else
                // 列举区间的分割点
                for (int k = l; k <= r; ++k) {
                    int temp;
                    if (k == l){
                        // 左端点为空
                        temp = s[k] + f[k + 1][r];
                    }else if(k == r){
                        // 右子树为空
                        temp = s[k] + f[l][k - 1];
                    }else{
                        // 左右子树都不为空
                        temp = s[k] + f[k + 1][r] * f[l][k - 1];
                    }
                    // 比较确定最大值的并进行记录
                    if (f[l][r] < temp) {
                        rp[l][r] = k;
                        f[l][r] = temp;
                    }
                }
        }
    }
    
    cout<<f[0][n];
    dfs(0,n);
    
    return f[0][n];
    
}

背包问题——买书

在这里插入图片描述

  • 标准的背包问题
个人实现
  • 标准的背包问题,但是是计算方案数量的,而且会存在重复方案的问题,需要去除重复?是一个问题,并不是那么好去掉重复的。
  • 但是如果一开始是按照顺序进行购买的,后续只会增加更贵的物品,我应该如何进行计算?
  • 方案数应该怎么计算?直接求,整个矩阵的累加和就行了。
  • 注意,这里有一个,所有书全部用来购买书,手里不能有剩钱。

这是一个重复背包问题,属实不会弄,该想想怎么弄了!

#include <iostream>

using namespace std;

const int N = 10010;
int f[N],n;
int w[4] = {10,20,50,100};



int main(){
    cin>>n;
    int sum = 0;
    if (n % 10 != 0) cout<<0<<endl;
    else {
        for (int i = 0; i < 4; ++i) {
            for (int j = n; j >= w[i]; j--) {
                f[j] = f[j - w[i]] + f[j];
            }
        }
        cout << sum;
        
    }
}
参考实现
  • 参考作者:一只野生彩色铅笔
    链接:https://www.acwing.com/solution/content/52967/
    来源:AcWing
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在这里插入图片描述

  • 下述方法还是很朴素的,确实如此,这道题暂时先跳过,这个方案转换公式是想到了,但是没有写出来。关键是他还有优化,下次再来吧,还要看redis,没那么多时间。
#include <iostream>

using namespace std;

const int N = 5, M = 1010;

int n = 4, m;
int v[N] = {0, 10, 20, 50, 100};
int f[N][M];

int main()
{
    //input
    cin >> m;

    //dp
    f[0][0] = 1;
    for (int i = 1; i <= n; ++ i)
    {
        for (int j = 0; j <= m; ++ j)
        {
            for (int k = 0; v[i] * k <= j; ++ k)
            {
                f[i][j] += f[i - 1][j - v[i] * k];
            }
        }
    }

    //output
    cout << f[n][m] << endl;

    return 0;
}

新作

移除元素

题目链接
在这里插入图片描述
在这里插入图片描述

个人实现

重点

  • 原地移除所有等于val的元素,后续的元素向前移动
  • 保证前k个元素是不等于val的,并且原来的顺序不变
  • nums的其余元素和nums的大小并不重要

实现思路

  • 两个指针,一个从前往后,一个从后往前
  • 从前往后的负责遍历对应的数组,判定当前的元素是否等于val,然后从后往前的元素负责将不相等的元素移动到从前往后的索引下方。

在这里插入图片描述

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {

        int i = 0,r = nums.size() - 1;
        for (; i <= r ; ++i) {
        if (nums[i] == val) {
            while (r >= 0 && nums[r] == val) r--;
            if (i <= r ) nums[i] = nums[r],r--;
            else return i;
        }
    }
        return i;
    }
};

总结

  • 做是做出来了 ,但是说实话,稀碎,明明是道简单的题目,但是还是调了很久,思路很快就想到了,但是总是遇到各种各样的bug。
  • 有以下几个细节需要注意
    • 凡是涉及到数组索引的,都要进行检测,防止数组越界。这次在遍历右指针的时候,有好几个地方都没有对指针进行检查,导致不断报错溢出,很难受。
参考思路
  • 这个思路太暴力了,时间复杂度比我的高,完整遍历了整个数组。不对,其实我也是遍历了整个数组,不过我是双指针。而且是反向的,不行,这样完全没有必要。

  • 就是两个指针

    • idx表示实际的指针,只有不同的时候才会赋值并且递增
    • i表示遍历的指针,如果不同就执行赋值,如果相同就跳过。
  • 老是会把问题想的太复杂

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
 int idx = 0;
    for (int i = 0; i < nums.size(); ++i) {
        if (nums[i] != val){
            nums[idx] = nums[i];
            idx ++;
        }
    }
    return idx;
    }
};

找出字符串中第一个匹配项的下标

  • 题目链接

在这里插入图片描述

个人实现

重点

  • 第一个字符串中找出第二个字符串的第一个匹配项目的下标
    • 第二个字符串是一个子串,然后在第一个字符串中找到字串出现的第一个索引位置

思路实现

  • 别把这个问题想的太复杂,这是一道简单题,并不是中等题,所以怎么想就怎么实现。
  • 最直白的方式,就是两个指针进行遍历

在这里插入图片描述

class Solution {
public:
    int strStr(string h, string n) {
        bool f;
        for (int i = 0; i < h.size(); ++i) {
            f = true;
            for (int j = 0; j < n.size(); ++j) {
                if (h[i + j] != n[j])   {
                    f = false;
                    break;   
                }
            }
            if (f)  return i;
    }
    return -1;
    }
};
参考实现
  • 跳过吧,这个是用KMP算法的模板题,没有必要!
  • 这里仅仅贴一个代码就行了。
class Solution {
public:
    int strStr(string s, string p) {
        if (p.empty()) return 0;
        int n = s.size(), m = p.size();
        s = ' ' + s, p = ' ' + p;

        vector<int> next(m + 1);
        for (int i = 2, j = 0; i <= m; i ++ ) {
            while (j && p[i] != p[j + 1]) j = next[j];
            if (p[i] == p[j + 1]) j ++ ;
            next[i] = j;
        }

        for (int i = 1, j = 0; i <= n; i ++ ) {
            while (j && s[i] != p[j + 1]) j = next[j];
            if (s[i] == p[j + 1]) j ++ ;
            if (j == m) return i - m;
        }

        return -1;
    }
};

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/347914/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

总结

  • 今天两道简单的leetcode做完了,发现自己容易把问题想复杂,完全没有意义,简单题,怎么想怎么来。
  • 然后算法题复习题,又被背包问题给难住了,实际上能够写出状态转移方程,但是觉得有点麻烦,那个完全背包问题就划水划过去了。明天重点看一下这道题,然后再随便找一道区间DP的新题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1851892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android中屏蔽 电源键长按、Home键、Home长按

“电源键长按”&#xff08;globalscreen&#xff09; “Home键”&#xff08;homekey&#xff09; “Home长按”&#xff08;recentapps&#xff09; 我们可以使用广播来实现&#xff0c;如&#xff1a; [java] view plain copy print ? package com.jumpinus.test; im…

系统架构师概述

引言 系统架构设计师是项目开发活动中的众多角色之一&#xff0c;它可以是一个小组或者一个人或者是一个团队&#xff0c;架构师包含建筑师&#xff0c;设计师&#xff0c;创造者&#xff0c;缔造者&#xff0c;可以说架构师就是我们社会各个领域的创造者和缔造者。从组织上划分…

基于simulink的PEM燃料电池控制系统建模与仿真,对比PID,积分分离以及滑模控制器

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 PID控制器 4.2 积分分离PID控制器 4.3 滑模控制器 5.完整工程文件 1.课题概述 基于simulink的PEM燃料电池控制系统建模与仿真,对比PID,积分分离以及滑模控制器。 2.系统仿真结果 &#xff08;完…

华为---OSPF被动接口配置(四)

9.4 OSPF被动接口配置 9.4.1 原理概述 OSPF被动接口也称抑制接口&#xff0c;成为被动接口后&#xff0c;将不会接收和发送OSPF报文。如果要使OSPF路由信息不被某一网络中的路由器获得且使本地路由器不接收网络中其他路由器发布的路由更新信息&#xff0c;即已运行在OSPF协议…

如何在 Ubuntu 12.04 VPS 上安装和配置基本的 LDAP 服务器

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 LDAP&#xff08;轻量级目录访问协议&#xff09;是一种通过文件和目录层次结构管理相关信息的协议&#xff0c;它可以从集中位置管…

【嵌入式Linux】i.MX6ULL 时钟树——理论分析

文章目录 0. 时钟树结构0.1 参考手册 Chapter 18​: Clock Controller Module (CCM)0.2 时钟信号路径 1. 时钟源——晶振1.1 外部低频时钟 - CKIL1.1.1 CKIL 同步到 IPG_CLK 解释 1.2 外部高频时钟 - CKIH 和 内部振荡器1.3 总结1.4 缩写补充 2. PLL时钟2.1 i.MX6U 芯片 PLL 时…

Android Studio 安卓手机上实现火柴人动画(Java源代码—Python)

android:layout_marginLeft“88dp” android:layout_marginTop“244dp” android:text“Python” android:textSize“25sp” app:layout_constraintStart_toStartOf“parent” app:layout_constraintTop_toTopOf“parent” /> </androidx.constraintlayout.widget.…

基于顺序存储的环形队列算法库构建

学习贺利坚老师基于数组的环形队列 数据结构之自建算法库——顺序环形队列_下空队列q中依次入队列数据元素abc-CSDN博客文章浏览阅读5.2k次&#xff0c;点赞6次&#xff0c;收藏6次。本文针对数据结构基础系列网络课程(3)&#xff1a;栈和队列中第9课时环形队列的存储及基本操…

用Visual Studio调试CMake项目并生成Visual Studio工程

一. 在Windows系统上安装CMake 访问CMake官方网站https://cmake.org/download&#xff0c;或通过文末链接下载&#xff1a;在下载页面上&#xff0c;找到并点击“Download”链接以获取最新的稳定版本的CMake。请注意&#xff0c;虽然新版本可能包含更多功能和改进&#xff0c;…

MATLAB | 怎样绘制这样的环形柱状图

Hey, 各位又是好久不见&#xff0c;最近忙到后台消息都有些来不及看&#xff0c;非常抱歉&#xff0c;今天带来一个环形柱状图绘制的简易小代码,绘制效果如下&#xff1a; 下面直接给出完整代码&#xff0c;替换一下数据即可&#xff0c;代码都有注释的&#xff1a; 完整代码 …

Redis—SortedSet数据类型及其常用命令详解

文章目录 一、Redis概述SortedSet类型1 ZADD&#xff1a;向有序集合添加成员2 ZREM&#xff1a;从有序集合中移除一个或多个成员3 ZSCORE : 获取sorted set中的指定元素的score值4 ZRANK&#xff1a;获取sorted set 中的指定元素的排名5 ZCARD&#xff1a;获取sorted set中的元…

库卡机器人减速机维修齿轮磨损故障

一、KUKA机器人减速器齿轮磨损故障的原因 1. 润滑不足&#xff1a;润滑油不足或质量不佳可能导致齿轮磨损。 2. 负载过重&#xff1a;超过库卡机械臂减速器额定负载可能导致齿轮磨损。 3. 操作不当&#xff1a;未按照说明书操作可能导致KUKA机器人减速器齿轮磨损。 4. 维护不足…

Unity Apple Vision Pro 开发(三):visionOS 应用形态

文章目录 &#x1f4d5;教程说明&#x1f4d5;常用名词解释&#x1f4d5;visionOS 空间类型⭐Shared Space 共享空间⭐Full Space/Immersive Space 独占空间 &#x1f4d5;visionOS 渲染框架&#x1f4d5;Unity 开发 visionOS 应用的不同模式⭐**窗口模式**⭐VR 模式⭐MR 模式 …

关于edge浏览器注册Kaggle不显示验证部分的问题

使用edge注册kaggle没有显示验证的部分导致无法完成注册 法一 谷歌大法好&#xff0c;使用谷歌注册就么有问题&#xff0c;然鹅需要魔法上网。 法二 使用 edge的Header Editor的插件 收到邮件后填写即可 参考博客&#xff1a; Kaggle平台注册弹不出验证码怎么办&#…

【C++LeetCode】【热题100】最长连续序列【中等】-不同效率的题解【5】

题目&#xff1a; 暴力方法&#xff1a; class Solution { public:int longestConsecutive(vector<int>& nums) {int maxlen1;//定义最长连续序列if(nums.size()<1){//特殊情况的长度 等于序列长度return nums.size();}std::unordered_set<int> uniqu…

内容安全复习 8 - 视觉内容伪造与检测

文章目录 研究背景内容伪造方法虚假人脸生成人脸替换属性编辑表情重演跨模态人脸编辑 伪造检测方法眨眼检测交互式人脸活体检测一些了解方法挑战 研究背景 图像内容篡改造成新闻报道的偏颇易导致社会和公共秩序的不安&#xff0c;对公共安全产生不良影响。 造成的影响&#x…

数据结构经典面试之列表——C#和C++篇

文章目录 1. 数据结构概述2. 列表&#xff08;List&#xff09;的基本概念与操作3. 列表的具体实现方式3.1 数组实现3.2 链表实现 4. 列表在C#和C中的使用示例4.1 C#中的列表使用示例4.2 C中的列表使用示例 5. 总结 数据结构是计算机科学中非常重要的一个领域&#xff0c;它主要…

vue-cli 根据文字生成pdf格式文件 jsPDF

1.安装jspdf npm install jspdf --save 2.下载ttf格式文件 也可以用C:\Windows\Fonts下的字体文件&#xff0c;反正调一个需要的ttf字体文件就行&#xff0c;但有的字体存在部分字体乱码现象 微软雅黑ttf下载地址&#xff1a; FontsMarket.com - Download Microsoft YaHei …

一种基于稀疏学习的旋转机械故障诊断方法(MATLAB)

稀疏表示方法是一种利用最少原子在过完备字典上表示或逼近信号的方法&#xff0c;该方法具有信号表示的高分辨率、稀疏性、强抗干扰能力和自适应性等优点。稀疏表示聚焦于设计合适的稀疏表示字典和挖掘有用的稀疏先验信息&#xff0c;其核心思想是将故障特征信息近似表示为字典…