【算法/训练】:动态规划(线性DP)

一、路径类

1. 字母收集

思路:

1、预处理

     对输入的字符矩阵我们按照要求将其转换为数字分数由于只能往下和往右走,因此走到(i,j)的位置要就是从(i - 1, j)往下走,或者是从(i,j  - 1)的位置往右走,由于我们要使得路程遍历积分最多,则应该从积分多的位置过来,

2、状态表示 dp[i][j] 表示:从[0, 0]出发,到底[i, j]位置,一共有多少分

3、状态转移方程

    故(i,j)位置的积分应该为dp[ i ][ j ] = max(dp[ i - 1 ][ j ], dp[ i ][ j - 1 ]) + dp[ i ][ j ];

4、初始化

    但是上面仅对于(i >= 1 && j >= 1)成立,对于第一行和第一列我们应该特殊处理,利用前缀和的知识可以求得,走到第一列的第i个位置最多能拿的积分以及走到第一行的第j个位置最多能拿的积分,然后我们就可以按照dp[ i ][ j ] = max(dp[ i - 1 ][ j ], dp[ i ][ j - 1 ]) + dp[ i ][ j ]的方法遍历每个节点即可

AC代码如下:

#include <iostream>
using namespace std;const int N = 1005;
int dp[N][N];int main() {int n, m;cin >> n >> m;char ch;for (int i = 0; i < n; i++){for (int j = 0; j < m; j++){cin >> ch;if (ch == 'l') dp[i][j] = 4;else if (ch == 'o') dp[i][j] = 3;else if (ch == 'v') dp[i][j] = 2;else if (ch == 'e') dp[i][j] = 1;else a[i][j] = 0;}}for (int i = 1; i < n; i++) dp[i][0] = dp[i - 1][0] + dp[i][0]; 
for (int j = 1; j < m; j++) dp[0][j] = dp[0][j - 1] + dp[0][j]; for (int i = 1; i < n; i++){for (int j = 1; j < m; j++){dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + dp[i][j];}}cout << dp[n - 1][m - 1] << endl;return 0;
}

2、[NOIP2002 普及组] 过河卒

分析:

思路:
1、状态表示
dp[i][j] 表示:从[0, 0]出发,到底[i, j]位置,一共有多少种方法
2、状态转移方程

    dp[ i ][ j ] = dp[ i - 1 ][ j ] + dp[i][j - 1] (i > 0 && j > 0)

当走到马可以走的地方,dp[ i ][ j ] = 0;
3、初始化

先创建一个 dp[ n + 2 ][ m + 2 ],然后让dp[ 0 ][ 1 ] = 1 或者 dp[ 1 ][ 0 ] = 1。注意这样初始化的时候,x需要+1,y也需要+1.和dp表位置一一对应

#include <iostream>
#include <vector>
using namespace std;//int dp[1005][1005];
int main()
{int n, m, x, y;cin >> n >> m >> x >> y;vector<vector<long long>> dp(n + 2, vector<long long>(m + 2));dp[0][1] = 1;x += 1, y += 1;和dp表位置一一对应for (int i = 1; i <= n + 1; i++){for (int j = 1; j <= m + 1; j++) { //马所在位置if (i != x && j != y && abs(i - x) + abs(j - y) == 3 || (i == x && j == y)){dp[i][j] == 0;}else dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}cout << dp[n + 1][m + 1] << endl;return 0;
}

二、子序列和连续序列类

1. mari和shiny

🌈线性 dp

在维护 i 位置之前,⼀共有多少个 "s" "sh" ,然后更新 "shy" 的个数。

(1)状态表示

  • s[i]:字符串 str 中 [0, i] 区间内有多少个 "s"。

  • h[i]:字符串 str 中 [0, i] 区间内有多少个 "sh"。

  • y[i]:字符串 str 中 [0, i] 区间内有多少个 "shy。


(2)状态转移方程


(3)空间优化

用三个变量来表示即可

s:(字符串 str 中 [0, n-1] 区间内有多少个 "s")

h:(字符串 str 中 [0, n-1] 区间内有多少个 "sh")

y:(字符串 str 中 [0, n-1] 区间内有多少个 "shy")

最后的遍历结束后,y即我们需要的结果

AC代码如下:

#include <iostream>
#include <string>
using namespace std;
typedef long long ll;
int main()
{int n;string str;cin >> n >> str;ll s = 0, h = 0, y = 0;for (int i = 0; i < n; i++) {if (str[i] == 's') s++;else if (str[i] == 'h') h += s;else if (str[i] == 'y') y += h;}cout << y << endl;return 0;
}
🌈二维 dp 

这道题目如果不是子序列,而是要求连续序列的,那就可以考虑用 KMP。

(1)dp[i][j] 含义

  • string t="shy"

dp[i][j]:以 i-1 为结尾的 str 子序列中出现以 j-1 为结尾的 t 的个数为 dp[i][j]。


(2)递推关系

  • str[i - 1] 与 t[j - 1]相等
  • str[i - 1] 与 t[j - 1] 不相等

当 str[i - 1] 与 t[j - 1]相等时,dp[i][j] 可以有两部分组成:

  1. 一部分是用 str[i - 1] 来匹配,那么个数为 dp[i - 1][j - 1]。即不需要考虑当前 str 子串和 t 子串的最后一位字母,所以只需要 dp[i-1][j-1]。
  2. 一部分是不用 str[i - 1] 来匹配,个数为 dp[i - 1][j]。

为什么还要考虑不用 str[i - 1] 来匹配,都相同了指定要匹配?
🧩例如: str:shyy 和 t:shy ,str[3] 和 t[2] 是相同的,但是字符串 str 也可以不用 str[3] 来匹配,即用 str[0]str[1]str[2] 组成的 "shy"。当然也可以用 str[3] 来匹配,即:str[0]str[1]str[3] 组成的 "shy"。

所以,当 str[i - 1] 与 t[j - 1] 相等时,dp[ i ][ j ] = dp[ i - 1 ][ j - 1 ] + dp[ i - 1 ][ j ];

当 str[i - 1] 与 t[j - 1] 不相等时,dp[i][j] 只有一部分组成,不用 str[i - 1] 来匹配(就是模拟在 str 中删除这个元素),即:dp[i - 1][j],所以递推公式为:dp[ i ][ j ] = dp[ i - 1 ][ j ];

为什么只考虑 “不用 str[i - 1] 来匹配” 这种情况, 不考虑 “不用 t[j - 1] 来匹配” 的情况呢?
🧩这里要明确,我们求的是 str 中有多少个 t,而不是求 t 中有多少个 str,所以只考虑 str 中删除元素的情况,即不用 str[i - 1] 来匹配 的情况。


(3)状态转移方程

  • dp[i][j]显然要从dp[i-1][?]递推而来。立即思考dp[i-1][j], dp[i-1][j-1]分别与dp[i][j]的关系。因为少一个字符,自然而然从当前字符着手。考察si的第i个字符(表为s[i])和tj的第j个字符(表为t[j])的关系。

  • 若s[i] ≠ t[j]:那么s_i中的所有t_j子序列,必不包含s[i],即s_i-1和s_i中tj的数量是一样的,得到该情形的转移方程: dp[ i ][ j ] = dp[ i -1 ][ j ]

  • 若s[i] = t[j]:假设s_i中的所有t_j子序列中,包含s[i]的有a个,不包含的有b个。s_i中包含s[i]的子序列个数相当于s_i-1中t_j-1的个数,不包含s[i]的子序列个数与上一种情况一样,于是得到该情形的转移方程:

    a = dp[ i -1 ][ j -1 ] b = dp[ i-1 ][ j ] dp[ i ][ j ] = a + b = dp[i-1][j-1] + dp[i-1][j]


(4)遍历顺序

从上到下,从左到右。

AC代码如下:

#include <iostream>
#include <vector>using namespace std;int main()
{int n;cin >> n;string str;cin >> str;string t="shy";int m=t.size();vector<vector<long long>> dp(n+1, vector<long long>(m+1));for(int i=0; i<=n; i++) dp[i][0]=1;for(int i=1; i<=n; i++){for(int j=1; j<=m; j++){if(str[i-1]==t[j-1])dp[i][j]=dp[i-1][j-1]+dp[i-1][j];elsedp[i][j]=dp[i-1][j];}}cout << dp[n][m] << endl;return 0;
}

2. 不同的子序列

该题于上题不一样的是,上面给定了t的具体字符串,而这里没有给定,但是我们也需要用二维dp的方法来写。

(1)dp[i][j] 含义

s[ i ]的子序列中在t[ j ]出现的次数

s[ i ]表示s从下标 i 到末尾的子字符串。

t[ j ]表示t从下标 j 到末尾的子字符串。


(2)递推关系

  1. 分别令两个维度为0,推测边界。
  2. dp[0][j]表示s_0中t_j的个数。s_0是空字符串,只有当j=0时,才有dp[0][j] = 1,表示s子空串中有一个t子空串,否则dp[0][j] = 0,因为一个空串不可能包含一个非空串。
  3. dp[i][0]表示s_i中t0的个数。t_0是空字符串,显然任何串(包括空串)都含有一个空子串。因此dp[i][0] = 1。

  4. 注意到,dp[i][0] = 1实际上已经包含了dp[0][j] = 1的情形。


(3)初始化

  • dp[i][0] 表示:以 i-1 为结尾的 str 可以随便删除元素,出现空字符串的个数。所以,dp[i][0] 一定都是 1,因为也就是把以 i-1 为结尾的 str,删除所有元素,出现空字符串的个数就是 1。
  • dp[0][j] 表示:空字符串 str 可以随便删除元素,出现以 j-1 为结尾的字符串 t 的个数。所以,dp[0][j] 一定都是 0,因为 str 如论如何也变成不了 t。
  • dp[0][0] 表示:空字符串 str 可以删除 0 个元素,变成空字符串 t。所以,dp[0][0] = 1。

(4)遍历顺序

从上到下,从左到右。

​
int numDistinct(string s, string t) {int n = s.size(), m = t.size();if (n < m) return 0;vector<vector<unsigned int>> dp(n + 1, vector<unsigned int>(m + 1)); //注意是unsigned intfor (int i = 0; i <= n; i++) dp[i][0] = 1;for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {dp[i][j] = dp[i - 1][j] +(s[i - 1] == t[j - 1] ? dp[i - 1][j - 1] : 0);}}return dp[n][m];
}​

三、偷盗问题

1. 打家劫舍

思路:

首先考虑最简单的情况。如果只有一间房屋,则偷窃该房屋,可以偷窃到最高总金额。如果只有两间房屋,则由于两间房屋相邻,不能同时偷窃,只能偷窃其中的一间房屋,因此选择其中金额较高的房屋进行偷窃,可以偷窃到最高总金额。

如果房屋数量大于两间,应该如何计算能够偷窃到的最高总金额呢?对于 k( k > 2)的房屋数量,有两个选项:

  • 偷窃第k间房屋,那么就不能偷窃第 k−1 间房屋,偷窃总金额为前 k−2 间房屋的最高总金额与第 k 间房屋的金额之和。
  • 不偷窃第 k 间房屋,偷窃总金额为前 k−1 间房屋的最高总金额。

    在两个选项中选择偷窃总金额较大的选项,该选项对应的偷窃总金额即为前 k 间房屋能偷窃到的最高总金额。

1、状态表示
dp[ i ]:表示前i间房屋能偷盗的最多钱数。
2、状态转移方程

    dp[ i ] = max(dp[ i - 2 ] + nums[ i ] , dp[i - 1] )

提示里说了nums.length>=1;

对于nums.length==1,需特殊处理,return nums[0];

AC代码如下:

int rob(vector<int>& nums) {int n = nums.size();//方法一/*if (n == 1) return nums[0];vector<int> dp(n + 1);dp[0] = nums[0];dp[1] = max(nums[0], nums[1]);for (int i = 2; i < n; ++i) {dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[n - 1];*///方法二int f1 = 0, f0 = 0;for (int i = 0; i < n; i++) {int tmp = max(f1, f0 + nums[i]);f0 = f1;f1 = tmp;}return f1;
}

2. 打家劫舍 II

思路:

    这道题中的房屋是首尾相连的,第一间房屋和最后一间房屋相邻,因此第一间房屋和最后一间房屋不能在同一晚上偷窃。和上题相似,这道题也可以使用动态规划解决。

考虑是否偷 nums[0]:

  • 如果偷 nums[0],那么 nums[1] 和 nums[n−1] 不能偷,问题变成从 nums[2] 到 nums[n−2] 的非环形版本。
  • 如果不偷 nums[0],那么问题变成从 nums[1] 到 nums[n−1] 的非环形版本。
  • 分别取 [start,end)=[2,n−2) 和 [start,end)=[1,n−1) 进行计算,取两个 dp[end] 中的最大值,即可得到最终结果

假设偷窃房屋的下标范围是 [start,end],用 dp[i] 表示在下标范围 [start,i] 内可以偷窃到的最高总金额:

1、状态表示
   dp[ i ]:表示前i间房屋能偷盗的最多钱数。
2、状态转移方程

    dp[i]=max(dp[i−2]+nums[i],dp[i−1])

注意:这题我们用 tmp, f1, f0 来分别表示dp[i],dp[i - 1],dp[i -2]。 

int robRange(vector<int>& nums, int start, int end) { // [start, end) 左闭右开int f1 = 0 , f0 = 0;for (int i = start; i < end; i++) {int tmp = max(f1, f0 + nums[i]);f0 = f1;f1 = tmp;}return f1;
}int rob(vector<int>& nums) {int n = nums.size();return max(nums[0] + robRange(nums, 2, n - 1), robRange(nums, 1, n));
}

3. 打家劫舍 III

思路:

对于当前节点,就两个选择,或者放弃然后我们用 f(o) 表示抢 o 节点的情况下,o 节点的子树上被选择的节点的最大权值和;g(o) 表示不抢 o 节点的情况下,o 节点的子树上被选择的节点的最大权值和;l 和 r 代表 o 的左右孩子。

🧩1、当 o 被选中时,o 的左右孩子都不能被选中,故 o 被选中情况下子树上被选中点的最大权值和为 l 和 r 不被选中的最大权值和相加,即 f(o)=g(l)+g(r)
🧩2、当 o 不被选中时,o 的左右孩子可以被选中,也可以不被选中。对于 o 的某个具体的孩子 x,它对 o 的贡献是 x 被选中和不被选中情况下权值和的较大值。故 g(o)=max{f(l),g(l)}+max{f(r),g(r)}
🧩至此,我们可以用哈希表来存 f 和 g 的函数值,用深度优先搜索的办法后序遍历这棵二叉树,我们就可以得到每一个节点的 f 和 g。根节点的 f 和 g 的最大值就是我们要找的答案。

unordered_map<TreeNode*, int>f, g;
void dfs(TreeNode* node)
{if (node == nullptr) return;dfs(node->left), dfs(node->right);f[node] = node->val + g[node->left] + g[node->right]; //如果抢该节点g[node] = max(f[node->left], g[node->left]) + max(f[node->right], g[node->right]);
}int rob(TreeNode* root) {dfs(root);return max(f[root], g[root]);
}

4. 打家劫舍 IV

思路:

     通过观察可以发现,当偷盗能力越大时,小偷最多能偷的房屋数就越多;如果偷盗能力越小时,小偷最多能偷的房屋数就越少。

     由题意我们可知,这是求最小的最大值,因此我们可以想到用二分的方法来找到合适的 capacity。对于每个通过二分列举出来的 capacity,因为碍于偷盗能力,小偷只能偷价值不超过 capacity 的房子,而且不能连续偷。因此,我们可以通过动态规划的方法算出:当小偷的偷盗能力为 capacity 时,小偷可以最多可以偷多少间房(设为 y),如果 y >= k,那么就代表 capacity 偏大,要把 capacity 调小一点;如果 y < k,那么就代表 capacity 偏小,把 capacity 调大一点。且由于要求的是最小的最大值,因此属于二分里面的区间左端点问题。

处。

     通过二分枚举 capacity,对每个 capacity 进行动态规划,求出在该 capacity 的情况下最多偷到的房屋数,然后再根据这个房屋数调整 capacity 的查找区间。

int minCapability(vector<int>& nums, int k) {vector<int> capacity = nums;sort(capacity.begin(), capacity.end());int l = 0, r = capacity.size() - 1;while (l < r){int m = (r - l >> 1) + l; //注意:+, -的优先级高于>>if (check(nums, capacity[m]) >= k)r = m;else l = m + 1;}return capacity[l];
}int check(vector<int>& nums, int capacity)
{int n = nums.size();vector<vector<int>> dp(n + 1, vector<int>(2));for (int i = 1; i <= n; i++){if (nums[i - 1] <= capacity) dp[i][1] = dp[i - 1][0] + 1;dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]);}return max(dp[n][1], dp[n][0]);
}

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

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

相关文章

前端面试基础题(微信公众号:前端面试成长之路)

BFC、IFC、GFC、FFC CSS2.1中只有BFC和IFC, CSS3中才有GFC和FFC。 到底什么是BFC、IFC、GFC和FFC Whats FC&#xff1f; 一定不是KFC&#xff0c;FC的全称是&#xff1a;Formatting Contexts&#xff0c;是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域&#xff0c;并…

免费【2024】springboot 宠物领养救助平台的开发与设计

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

普元EOS学习笔记-EOS项目HTTP访问安全和权限控制

前言 对于企业应用系统&#xff0c;出于安全和权限控制的目的&#xff0c;需要对http请求做若干控制。 比如文件上传的时候要控制不允许上传的文件后缀。 又比如控制应用程序中的哪些资源不允许被访问。 EOS项目通过 xml配置文件来实现这一需求。 Http访问管理模块 在EOS项…

【C++版本】protobuf与gRPC

文章目录 一、Protobuf二、安装以及使用protoc参考 一、Protobuf Google Protocol Buffers&#xff08;protobuf&#xff09;是一种语言中立、平台中立的序列化协议&#xff0c;旨在高效地将结构化数据进行序列化和反序列化。它主要用于通信协议、数据存储和其他需要高效编码和…

封装和桥接Unity 协程体系

简介 协程&#xff08;Coroutine&#xff09;在C#中是一种特殊的函数&#xff0c;它允许开发者编写可以暂停执行并在未来某个时刻恢复执行的代码块。协程通常用于实现异步操作&#xff0c;如延时执行、等待某个事件发生、或者分段执行复杂的任务。在Unity游戏引擎中&#xff0c…

(Arxiv-2023)MobileDiffusion:移动设备上即时文本到图像生成

MobileDiffusion&#xff1a;移动设备上即时文本到图像生成 Paper Title&#xff1a;MobileDiffusion: Instant Text-to-Image Generation on Mobile Devices Paper是谷歌出品 Paper地址 图 1&#xff1a;MobileDiffusion 用于 (a) 文本到图像的生成。(b) Canny 边缘到图像、风…

docker容器cuda不可用,怎么解决?

通过Docker 构建的镜像中,启动之后,发现容器内部读取不到显卡驱动nvidia-smi 1、设置 NVIDIA Docker 存储库 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add

Docker容器基础篇

一.Docker容器简要介绍 Docker 是一个开源项目&#xff0c;旨在提供轻量级的应用容器化解决方案。它允许开发者打包应用及其所有依赖项到一个标准化的单元中&#xff0c;称为容器。这些容器可以在开发人员的工作环境中构建&#xff0c;然后轻松地在不同的计算机、服务器或云平…

Redis的分布式锁

目录 一、定义与原理 基于Redis的分布式锁 获取锁 释放锁 锁误删问题&#xff1a;因为key值一样,将别人的锁删掉了 锁误判问题二&#xff1a;判断锁和释放锁不是原子性的 Lua脚本 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁 分布式锁的优点…

Spring Cache常用注解

依赖代码如下&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency> 常用注解详解 1. Cacheable 作用&#xff1a;主要用于配置方法&#xff0c;使其…

Java编写SIP协议

1、编写Server代码 package com.genersoft.iot.vmp.sip; import javax.sip.*; import javax.sip.message.*; import javax.sip.header.*; import java.util.*;public class SimpleSipServer implements SipListener {private SipFactory sipFactory;private SipStack sipStack…

【前端】一文带你了解 CSS

文章目录 1. CSS 是什么2. CSS 引入方式2.1 内部样式2.2 外部样式2.3 内联样式 3. CSS 常见选择器3.1 基础选择器3.1.1 标签选择器3.1.2 类选择器3.1.3 id 选择器3.1.4 通配符选择器 3.2 复合选择器3.2.1 后代选择器 4. CSS 常用属性4.1 字体相关4.2 文本相关4.3 背景相关4.4 设…

前端必备基础【网络通信】(2024最新版)

Ajax Asynchronous Javascript and XML 的缩写&#xff0c;是使用 JS 发起网络通信的技术统称&#xff0c;具体步骤为&#xff1a; 创建 XMLHttpRequest 实例发出 HTTP 请求接收服务器传回的数据更新网页数据&#xff08;通常是部分内容&#xff0c;而不是整个网页&#xff09…

LLM - 理解 大模型 Batch 推理的 Padding Side (左填充或右填充)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/140697827 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 使用 Left Padding (左填充) 或者 Right Padding (右填充),HuggingFac…

DBeaver安装与使用教程 免费的连接mysql数据库软件

一、DBeaver安装 &#xff08;一&#xff09;Dbeaver下载 DBeaver 是一个通用的数据库管理工具和 SQL 客户端&#xff0c;免费&#xff0c;跨平台&#xff0c;支持 MySQL, PostgreSQL, Oracle, DB2, MSSQL, Sybase, Mimer, HSQLDB, Derby, 以及其他兼容 JDBC 的数据库。 官网…

带你学会Git必会操作

文章目录 带你学会Git必会操作1Git的安装2.Git基本操作2.1本地仓库的创建2.2配置本地仓库 3.认识一些Git的基本概念3.1操作流程&#xff1a; 4.一些使用场景4.1添加文件场景一4.2查看git文件4.3修改文件4.4Git版本回退4.5git撤销修改 5.分支管理5.1查看分支5.2创建本地分支5.3切…

【C++进阶】AVL树详解

文章目录 1. AVL树的概念2. AVL树结点的定义3. AVL 树的插入3.1 关于平衡因子3.2 插入代码 4. AVL 树的旋转逻辑4.1 不需要旋转4.2 左旋4.3 右旋4.4 双旋4.4.1 先右后左单旋&#xff08;RL 旋转&#xff09;4.4.2 先左后右单旋&#xff08;LR 旋转&#xff09; 4.5 完整插入代码…

C语言 | Leetcode C语言题解之第301题删除无效的括号

题目&#xff1a; 题解&#xff1a; struct Next { int l, r, cl, cr; };void vec_push(char*** v, int* n, char* s) {if (!(*n & *n1)) {*v realloc(*v, sizeof(char*) * ((*n << 1) | 1));}(*v)[(*n)] s; }void dfs(const char* s, int i, struct Next next[],…

图片格式怎么转换?这几种图片格式转换方法简单又高效

图片已成为我们日常生活与工作中不可或缺的一部分。然而&#xff0c;不同平台和应用往往对图片格式有着特定的要求&#xff0c;这就使得图片格式的转换成为了一项必备技能。下面给大家分享5种能够简单高效的转换图片格式方法&#xff0c;快来一起学习下吧。 方法一&#xff1a;…

JavaFX布局-TitledPane

JavaFX布局-TitledPane 常用属性textcontentgraphicexpandedcollapsibleanimated 实现方式Javafxml 提供了一个可折叠的标题栏和一个内容区域内容区域可以嵌套其他布局 常用属性 text 设置标题 titledPane.setText("测试标题");content 内容区域&#xff0c;可以单…