思路
思路一
看到这种题,我们首先想到的就是暴力解法,双层循环遍历,求出对应的值,与最大值进行比较即可。
过程如下:
-
数据声明
(1)最大分数,用于比较和返回结果
(2)数组的长度,用于循环条件 -
双层循环,第一层循环从0开始,到len-1结束,第二层循环从1开始到len结束
每次循环计算出目标值与最大值进行比较更新
代码
class Solution {
public:
int maxScoreSightseeingPair(vector<int>& A) {
int maxScore = 0;
int len = A.size();
for(int i=0;i<len-1;i++) {
for(int j=i+1;j<len;j++) {
maxScore = max(maxScore, A[i]+A[j]+i-j);
}
}
return maxScore;
}
};
很明显,时间复杂度是O(n^2),题目肯定不会这么简单地通过地,果然提交后会超时。
思路二
碰到这种多层循环的题我们要想办法转换成更少的循环层数,仔细分析要计算的值为A[i]+i+A[j]-j,我们可以针对每一个A[j]-j,求出以j为结束时,其的最大值,这时候我们只需要找到A[i]+i的最大值即可,因为i在j前面,如果我们j从1开始遍历的话,每次遍历的过程中就可以更新得到j前面A[i]+i的最大值,不用再一次遍历。
过程:
-
数据声明
(1)保存当前最大分数的变量rst
(2)数组长度len,用于判断循环结束条件
(3)保存当前A[i]+i的最大值的变量max_score -
从下标1开始遍历数组,求出以当前元素为j元素时,得分的最大值,并以此更新rst(最初max_score的最大值为下标为0时的A[i]+i),同时需要通过当前元素更新max_score
-
rst即为结果
代码
class Solution {
public:
int maxScoreSightseeingPair(vector<int>& A) {
int rst = 0;
int len = A.size();
int max_score = A[0] + 0;
for(int i=1;i<len;i++) {
rst = max(rst, max_score+A[i] - i);
max_score = max(max_score, A[i] + i);
}
return rst;
}
};
很明显此时时间复杂度变为了O(n)
总结
1、对于双层循环暴力解法一定要想办法将双层循环变成单层循环
2、对于双层循环求多个元素最大值的问题(是有一定的重复),我们可以通过求元素较少时的最大值,然后不断更新最大值,比如求一个数组中两个元素和的最大值,不能使用排序,我们可以双层循环,但是也可以通过最大值的另一种求法变成单层循环。本题中,双层循环其实是,以每个i为参考点,求j的最大值,然而在求j的最大值过程中,由于元素很多,避免不了有很多重复的过程,然而优化成单层循环是以每个j为参考点,将j的下标压缩到较小位置,求i的最大值,这个时候,我们就能在更新j的过程中同时更新j之前i的最大值。