淼淼刷力扣

引言

本人初次尝试写博客,希望各位看官大佬多多包容
有错误希望巨巨们提出来,我一定会及时改正,谢谢大家
在自己最好的年纪,找到了未来的目标
还有1年奋斗刷题,明年去面试实习,加油!

题目一要求:

在这里插入图片描述
在这里插入图片描述

整体思路

为什么想到了DP?

这题乍一看,给个环,环上有珠子,问我咋捏爆珠子,才能获得最大效益,典型的,给个环(或者一个序列),找"最优"状态问题,完全可以上马DP。
(下方的分析就是区间DP常用的模板)

1、找状态

在一个环上区间DP,必备i,j表示区间开头和结尾,剩下的就什么都不需要表示了,综上,两个状态i,j

2、初始化

因为最开始只有一个珠子的时候没能量,所以是0.

3、找转移

<一定记住:大的区间最优是通过小区间最优转化+当此消耗而来。>
区间DP最常用模板:即枚举所有小区间,在所有小区间中找到最优再加上当前区间消耗
在这里插入图片描述
再回到本题,很明显,大区间i,j它能产生多少能量,完全取决于子区间,因为我们通过看题中的计算方法样例:
在这里插入图片描述
当我们合并i=4,j=2这个区间时,先41再2,和先12再4,自己算一下是明显不同的,再加之当前区间消耗也不是固定的(这个是该题重点),所以必须是小区间+选择了该小区间后大区间消耗,二者叠加产生最优值,我们才会选。
综上:dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i] * a[k + 1] * a[j + 1]);就是状态转移方程,这里一定要注意的是,本区间消耗收到所选择的小区间影响,所以必须和小区间绑定相加。
(其实从这里也就看出来为啥这题不能贪心,就算是小区间你选择了最大利益化,但是可能加上本次的消耗后,综合起来的利益就未必最大了,可能有的小区间所获了利益并不太理想,但是一旦加上了当此产生利益反而大了,所以我们DP选择的是综合最大化)

4、找答案

因为是环状处理,所以在一个环上,从任意一个节点断开开始从前到后捏珠子产生的能量不同,所以必须每个段点产生的链都看一遍找最大的。

具体代码(内附注释)

1、因为这是一个环,所以采用了环状处理大法,将1到n-1再抄一遍,具体分析见我的另一篇博客有详解石子合并
2、大区间本次的消耗参考题中给的例子:
在这里插入图片描述
当我们合并i=4,j=2这个区间时,假设子区间是4和1,那么现在只需要将剩下两个珠子(因为41合并之后会留下一颗珠子,总共三颗珠子),我们看上方第二个乘法表达式,肯定有a[i]=10,k=1,a[k+1]=3,a[j+1]=5,所以表达式拼出来了。
3、遇到这种环或者一个序列上的DP问题时候,我们需要从小到大找区间,所以会有一个双层for循环:
在这里插入图片描述
外层控制步伐,里层控制从何处开始找,而这搭配枚举区间。
4、在上面那个双层for循环时候,如果是环,外层初始是2,序列的时候,初始是1。

#include <string>
#include <stack>
#include <queue>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>//头文件不用这么多,我是写别的时候附带着就写上去了
using namespace std;
int dp[550][550] = { 0 };
int a[550];
int n;
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		a[i + n] = a[i];
	}
	for (int len = 2; len <= n; len++) {//控制步伐大小
		for (int i = 1, j; i + len <= 2*n; i++) {//控制区间起点,这样二者一配合就可以完美的枚举每个区间了
			j = i + len - 1;
			dp[i][j] = 0;
			for (int k = i; k < j; k++) {
				dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i] * a[k + 1] * a[j + 1]);//状态转移。
			}
		}
	}
	int Max = 0;
	for (int i = 1; i <= n; i++) {
		Max = max(Max, dp[i][i + n - 1]);//找答案
	}
	cout << Max;
}

(所有代码均已运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

时间复杂度:O(n^2)

题目二要求:

做完了DP,实在是没精力了,就做了到签到题找找感觉,哈哈哈。
在这里插入图片描述

整体思路

超级简单,就是做出两个指针,一个i从头开始,一个(num-i-1)从尾部开始,交换二者数据, 交换完数据I++,num-i-1自然向前移动了,重复上述过程即可。

具体代码(内附注释)

class Solution {
public:
	void reverseString(vector<char>& s) {
		int num = s.size();
		for (int i = 0; i < num / 2; i++) {
			swap(s[i], s[num - 1 - i]);
		}
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JLU_LYM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值