当前位置: 首页 > news >正文

LeetCode 2811. Check if it is Possible to Split Array【脑筋急转弯;前缀和+动态规划或记忆化DFS】中等

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给你一个长度为 n 的数组 nums 和一个整数 m 。请你判断能否执行一系列操作,将数组拆分成 n 个 非空 数组。

在每一步操作中,你可以选择一个 长度至少为 2 的现有数组(之前步骤的结果) 并将其拆分成 2 个子数组,而得到的 每个 子数组,至少 需要满足以下条件之一:

  • 子数组的长度为 1 ,或者
  • 子数组元素之和 大于或等于  m 。

如果你可以将给定数组拆分成 n 个满足要求的数组,返回 true ;否则,返回 false 。

注意: 子数组是数组中的一个连续非空元素序列。

示例 1:

输入:nums = [2, 2, 1], m = 4
输出:true
解释:
第 1 步,将数组 nums 拆分成 [2, 2][1] 。
第 2 步,将数组 [2, 2] 拆分成 [2][2] 。
因此,答案为 true

示例 2:

输入:nums = [2, 1, 3], m = 5 
输出:false
解释:
存在两种不同的拆分方法:
第 1 种,将数组 nums 拆分成 [2, 1][3] 。
第 2 种,将数组 nums 拆分成 [2][1, 3] 。
然而,这两种方法都不满足题意。因此,答案为 false

示例 3:

输入:nums = [2, 3, 3, 2, 3], m = 6
输出:true
解释:
第 1 步,将数组 nums 拆分成 [2, 3, 3, 2][3] 。
第 2 步,将数组 [2, 3, 3, 2] 拆分成 [2, 3, 3][2] 。
第 3 步,将数组 [2, 3, 3] 拆分成 [2][3, 3] 。
第 4 步,将数组 [3, 3] 拆分成 [3][3] 。
因此,答案为 true

提示:

  • 1 <= n == nums.length <= 100
  • 1 <= nums[i] <= 100
  • 1 <= m <= 200

解法1 记忆化DFS/区间DP+前缀和

为了方便求出子数组的和,我们使用前缀和。

对于数组拆分,很自然地想到DFS,但如果每次都在数组两侧拆分,则复杂度可能到 O ( 2 100 ) O(2^{100}) O(2100) ,为此必须使用记忆化+DFS。我个人的写法如下所示,令 d f s ( l , r ) dfs(l, r) dfs(l,r) 表示区间 [ l , r ] [l,r] [l,r] 可否拆分:

  • 递归边界:区间长度 ≤ 2 \le 2 2 ,一定可拆分在区间长度 > 2 > 2 >2 且区间和 ≤ m \le m m 时,此时无论如何都无法继续拆分下去
  • 递归过程:只有区间和大于 m m m可以拆分出子区间 [ l + 1 , r ] [l + 1, r] [l+1,r] [ l , r − 1 ] [l, r - 1] [l,r1](对应区间长度为 1 1 1 或区间和 ≥ m \ge m m ),且满足子区间可拆分——即 d f s ( l + 1 , r ) = t r u e dfs(l + 1, r) = true dfs(l+1,r)=true d f s ( l , r − 1 ) = t r u e dfs(l, r - 1)= true dfs(l,r1)=true ,此时区间 [ l , r ] [l, r] [l,r] 可以拆分。
class Solution {
private:int m;int sum[110];int dp[110][110];int dfs(int l, int r) {if (dp[l][r] != -1) return dp[l][r]; // 已经有答案if (l + 1 >= r) return dp[l][r] = 1; // 拆分前进行判断,可以拆分if (sum[r + 1] - sum[l] <= m) return dp[l][r] = 0; // 拆分前进行判断,不可拆分int left = 0, right = 0;if (l + 1 == r || sum[r + 1] - sum[l + 1] >= m) // 看是否可以拆分出[l+1,r]这个子数组left = dfs(l + 1, r); // 看[l+1,r]子数组是否可继续拆分if (l == r - 1 || sum[r] - sum[l] >= m) // 看是否可以拆分出[l,r-1]这个子数组right = dfs(l, r - 1); // 看[l,r-1]子数组是否可继续拆分return dp[l][r] = left || right; }
public:bool canSplitArray(vector<int>& nums, int m) {this->m = m;memset(sum, 0, sizeof(sum));memset(dp, -1, sizeof(dp));int n = nums.size();for (int i = 0; i < n; ++i) sum[i + 1] = sum[i] + nums[i];return dfs(0, n - 1);}
};

还可使用区间DP:

class Solution {
public:bool canSplitArray(vector<int>& nums, int m) {int sum[110];bool dp[110][110];memset(sum, 0, sizeof(sum));memset(dp, false, sizeof(dp));int n = nums.size();for (int i = 0; i < n; ++i) sum[i + 1] = sum[i] + nums[i];// dp[i][j]表示区间[i,j]能否拆分for (int i = n - 1; i >= 0; --i) {dp[i][i] = true;if (i + 1 < n) dp[i][i + 1] = true;// 区间[i,j-1], [i+1,j]是否可拆for (int j = i + 2; j < n; ++j) {// [i,j]能否拆分为[i+1,j]或[i,j-1],看拆出子数组的和是否>=m,且拆出子数组是否可继续拆分if (sum[j] - sum[i] >= m && dp[i][j - 1]|| sum[j + 1] - sum[i + 1] >= m && dp[i + 1][j])dp[i][j] = true;        }}return dp[0][n - 1];}
};

解法2 脑筋急转弯(最优解法)

要善于将题目转换成另外一种解法,对题目的理解、数学逻辑要求较高。

  • 先特判 n ≤ 2 n \le 2 n2 的情况,这是满足要求的。
  • 对于 n ≥ 3 n\ge 3 n3 的情况,无论按照何种方式分割,一定会在某个时刻,分割出一个长为 2 2 2 的子数组
    • 如果 nums \textit{nums} nums 中任何长为 2 2 2 的子数组的元素和都小于 m m m ,那么无法满足要求
    • 否则,可以用这个子数组作为「核心」,像剥洋葱一样,一个一个地去掉 nums \textit{nums} nums 的首尾元素,最后得到这个子数组。由于子数组的元素和 ≥ m \ge m m ,所以每次分割出一个元素时,剩余的子数组的元素和也必然是 ≥ m \ge m m 的,满足要求。

于是本题可转换成:求数组中是否存在2个相邻元素之和 ≥ m \ge m m 。相信题目如果这么问,100%的人都能做出来。

class Solution {
public:bool canSplitArray(vector<int>& nums, int m) {int n = nums.size();for (int i = 1; i < n; ++i)if (nums[i - 1] + nums[i] >= m) return true;return n <= 2;}
};

相关文章:

LeetCode 2811. Check if it is Possible to Split Array【脑筋急转弯;前缀和+动态规划或记忆化DFS】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

【学习日记】【FreeRTOS】链表结构体及函数详解

写在前面 本文主要是对于 FreeRTOS 中链表相关内容的详细解释&#xff0c;代码大部分参考了野火FreeRTOS教程配套源码&#xff0c;作了一小部分修改。 一、结构体定义 主要包含三种结构体&#xff1a; 普通节点结构体结尾节点&#xff08;mini节点&#xff09;结构体链表结…...

【云原生•监控】基于Prometheus实现自定义指标弹性伸缩(HPA)

【云原生•监控】基于Prometheus实现自定义指标弹性伸缩(HPA) 什么是弹性伸缩 「Autoscaling即弹性伸缩&#xff0c;是Kubernetes中的一种非常核心的功能&#xff0c;它可以根据给定的指标&#xff08;例如 CPU 或内存&#xff09;自动缩放Pod副本&#xff0c;从而可以更好地管…...

Windows、 Linux 等操作系统的基本概念及其常见操作

Windows 和 Linux 是两种常见的操作系统&#xff0c;它们在计算机领域中广泛使用。下面我将为您介绍它们的基本概念以及一些常见的操作。 **Windows 操作系统&#xff1a;** 1. **基本概念&#xff1a;** Windows 是由微软公司开发的操作系统系列&#xff0c;旨在为个人计算机…...

【RabbitMQ】golang客户端教程5——使用topic交换器

topic交换器&#xff08;主题交换器&#xff09; 发送到topic交换器的消息不能具有随意的routing_key——它必须是单词列表&#xff0c;以点分隔。这些词可以是任何东西&#xff0c;但通常它们指定与消息相关的某些功能。一些有效的routing_key示例&#xff1a;“stock.usd.ny…...

SpringBoot对接OpenAI

SpringBoot对接OpenAI 随着人工智能技术的飞速发展&#xff0c;越来越多的开发者希望将智能功能集成到自己的应用中&#xff0c;以提升用户体验和应用的功能。OpenAI作为一家领先的人工智能公司&#xff0c;提供了许多先进的自然语言处理和语言生成模型&#xff0c;其中包括深…...

(C++)继承

目录 1.继承的概念及定义 1.1继承的概念 1.2继承定义 1.2.1定义格式 1.2.2继承方式和访问限定符 1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 5.继承与友元 6.继承与静态成员 7.复杂的菱形继承及菱形虚拟…...

图像处理技巧形态学滤波之膨胀操作

1. 引言 欢迎回来&#xff0c;我的图像处理爱好者们&#xff01;今天&#xff0c;让我们继续研究图像处理领域中的形态学计算。在本篇中&#xff0c;我们将重点介绍腐蚀操作的反向效果膨胀操作。 闲话少说&#xff0c;我们直接开始吧&#xff01; 2. 膨胀操作原理 膨胀操作…...

机器学习基础之《特征工程(4)—特征降维》

一、什么是特征降维 降维是指在某些限定条件下&#xff0c;降低随机变量&#xff08;特征&#xff09;个数&#xff0c;得到一组“不相关”主变量的过程 1、降维 降低维度 ndarry 维数&#xff1a;嵌套的层数 0维&#xff1a;标量&#xff0c;具体的数0 1 2 3... …...

学生管理系统(Python版本)

class Student:def __init__(self, id, name, age):self.id idself.name nameself.age ageclass StudentManagementSystem:def __init__(self):self.students []def add_student(self, student):self.students.append(student)print("学生信息添加成功&#xff01;&qu…...

Linux下快速创建大文件的4种方法总结

1、使用 dd 命令创建大文件 dd 命令用于复制和转换文件&#xff0c;它最常见的用途是创建实时 Linux USB。dd 命令是实际写入硬盘&#xff0c;文件产生的速度取决于硬盘的读写速度&#xff0c;根据文件的大小&#xff0c;该命令将需要一些时间才能完成。 假设我们要创建一个名…...

用 Rufus 制作 Ubuntu 系统启动盘时,选择分区类型为MBR还是GPT?

当使用 Rufus 制作 Ubuntu 系统启动盘时&#xff0c;您可以根据您的需求选择分区类型&#xff0c;MBR&#xff08;Master Boot Record&#xff09;还是 GPT&#xff08;GUID Partition Table&#xff09;。 MBR 是传统的分区表格式&#xff0c;适用于大多数旧版本的操作系统和旧…...

Nodejs+vue+elementui汽车租赁管理系统_1ma2x

语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode 前端nodejsvueelementui, 课题主要分为三大模块&#xff1a;即管理员模块、用户模块和普通管理员模块&#xff0c;主要功能包括&#…...

Prometheus入门

Prometheus(普罗米修斯) 是一种 新型监控告警工具,Kubernetes 的流行带动了 Prometheus 的应用。 全文参考自 prometheus 学习笔记(1)-mac 单机版环境搭建[1] Mac 上安装 Prometheus brew install prometheus 安装路径在 /usr/local/Cellar/prometheus/2.20.1, 配置文件在 /usr…...

RISC-V云测平台:Compiling The Fedora Linux Kernel Natively on RISC-V

注释&#xff1a;编译Fedora&#xff0c;HS-2 64核RISC-V服务器比Ryzen5700x快两倍&#xff01; --- 以下是blog 正文 --- # Compiling The Fedora Linux Kernel Natively on RISC-V ## Fedora RISC-V Support There is ongoing work to Fedora to support RISC-V hardwar…...

Vim学习(三)—— Git Repo Gerrit

Git、Gerrit、Repo三者的概念及使用 三者各自作用&#xff1a; git&#xff1a;版本管理库&#xff0c;在git库中没有中心服务器的概念&#xff0c;真正的分布式。 repo&#xff1a;repo就是多个git库的管理工具。如果是多个git库同时管理&#xff0c;可以使用repo。当然使用…...

论坛项目之用户部分

注册接口 实现思路 1.特殊字段检查&#xff08;比如性别没有给出需要给出默认值&#xff09; 2.对比检查两次输入的密码是否一致&#xff0c;不一致报错 3.利用UUID生成随机‘盐’值&#xff0c;并使用密码进行MD5加密后与‘盐’进行拼接&#xff0c;生成加密后的密码 4.创建U…...

golang内存对齐

为什么要内存对齐&#xff1f; CPU访问内存时&#xff0c;以CPU的位数为单位进行访问。 如果访问未对齐的内存&#xff0c;处理器需要做两次内存访问&#xff0c;对齐的内存的访问可能仅需要一次&#xff0c;利用内存对齐后提升读取速度。 golang结构体内存对齐规则 在代码编译…...

【CheatSheet】Python、R、Julia数据科学编程极简入门

《Python、R、Julia数据科学编程极简入门》PDF版&#xff0c;是我和小伙伴一起整理的备忘清单&#xff0c;帮助大家10分钟快速入门数据科学编程。 另外&#xff0c;最近 TIOBE 公布了 2023 年 8 月的编程语言排行榜。 Julia 在本月榜单中实现历史性突破&#xff0c;成功跻身 …...

【golang】怎样判断一个变量的类型?

怎样判断一个变量的类型&#xff1f; package mainimport "fmt"var container []string{"zero", "one", "two"} func main() {container : map[int]string{0: "zero", 1: "one", 2: "two"}fmt.Printf…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...