问题描述
小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values
中,其中 values[i]
表示第 i
个观光景点的评分。同时,景点之间的距离由它们的下标差 j - i
表示。
一对景点 (i < j)
的观光组合得分为 values[i] + values[j] + i - j
,也就是两者评分之和减去它们之间的距离。
小R想知道,在哪种情况下能够获得观光景点组合的最高得分。
测试样例
样例1:
输入:
values = [8, 3, 5, 5, 6]
输出:11
样例2:
输入:
values = [10, 4, 8, 7]
输出:16
样例3:
输入:
values = [1, 2, 3, 4, 5]
输出:8
思路分析
根据题目分析我们可以使用双层循环来解决这个问题,第一次循环一次遍历每个景点,在下一次循环,则遍历景点数组中该景点之后的景点,依次使用得分公式,来计算景点的得分,再定义一个变量就可以记录景点组合的最高得分,然后返回该得分。
代码
int solution(int values[], int size) {
// write code here
int max=0;
int m,n,l,k;
for(int i=0;i<size;i++){
for(int j=i+1;j<size;j++){
int k= values[i] + values[j] + i - j;
if(k>max){
max=k;
m=values[i];
n=values[j];
l=i;
k=j;
}
}
}
return max; // Placeholder return
}
int main() {
int values1[] = {8, 3, 5, 5, 6};
printf("%d\n", (solution(values1, 5) == 11) ? 1 : 0);
int values2[] = {10, 4, 8, 7};
printf("%d\n", (solution(values2, 4) == 16) ? 1 : 0);
int values3[] = {1, 2, 3, 4, 5};
printf("%d\n", (solution(values3, 5) == 8) ? 1 : 0);
return 0;
}
代码解析
solution
函数
-
双层循环遍历:
- 在
solution
函数中,通过两层for
循环来遍历数组values
中的所有可能的景点组合。外层循环控制起始景点的下标i
,从数组的第一个元素开始(i = 0
),到倒数第二个元素结束(i < size - 1
),因为内层循环需要保证j > i
。 - 内层循环控制结束景点的下标
j
,从i + 1
开始,到数组的最后一个元素结束(j < size
)。这样就可以遍历到所有满足i < j
的景点组合情况。
- 在
-
计算组合得分并更新最大值:
- 对于每一对景点组合(
i
和j
),根据给定的公式values[i] + values[j] + i - j
计算它们的观光组合得分,将结果保存在变量k
中。 - 然后将这个得分
k
与当前记录的最大得分max
进行比较。如果k
大于max
,则说明找到了一个新的更高得分的组合,此时更新max
的值为k
,并且记录下这对景点的评分(m = values[i]
,n = values[j]
)以及它们的下标(l = i
,k = j
,这里内层循环中重复使用了k
变量名,可能会引起一些混淆,建议修改为不同的变量名)。
- 对于每一对景点组合(
main
函数
- 在
main
函数中,定义了三组不同的观光景点评分数组values1
、values2
和values3
,分别调用solution
函数计算它们各自的最高观光组合得分,并通过与预期得分进行比较,使用条件表达式(solution(valuesX, sizeX) == expectedScore)? 1 : 0
将比较结果输出为1
(表示计算结果与预期得分相符)或0
(表示计算结果与预期得分不符)。
知识点总结
代码中双层循环总结
在你提供的代码中,solution
函数里使用了双层循环来遍历数组values
以找出观光景点组合的最高得分。
-
外层循环:通过
for(int i = 0; i < size; i++)
控制起始景点的下标i
,从数组的第一个元素开始,逐步遍历到数组的倒数第二个元素(因为内层循环要保证j > i
)。 -
内层循环:对于外层循环确定的每个
i
值,内层循环for(int j = i + 1; j < size; j++)
从i + 1
开始,遍历到数组的最后一个元素,这样就确保了能遍历到所有满足i < j
的景点组合情况。
在双层循环内部,对于每一对确定的i
和j
(即每一个景点组合),根据给定的公式计算其观光组合得分,并与当前记录的最大得分进行比较,若大于最大得分则更新相关记录。
何时可以使用双层循环
双层循环常用于处理需要对二维数据结构(如二维数组)进行遍历操作,或者在一维数据结构(如数组、链表等)中需要考虑元素之间的两两组合关系等情况。具体如下:
- 二维数据结构遍历:当面对二维数组时,通常外层循环用于遍历行,内层循环用于遍历列,从而实现对整个二维数组中每个元素的访问。例如,在处理矩阵相关的运算、图像像素处理等场景中经常会用到。
- 元素两两组合情况:像在本题中,要找出数组中所有满足特定条件(
i < j
)的元素两两组合,并对每个组合进行某种计算或操作时,就可以使用双层循环。其他类似的场景还包括在一组数据中找出所有可能的子集对、对列表中的元素进行两两比较等。
双层循环的优点
- 逻辑清晰简单:双层循环的结构使得代码的逻辑相对清晰易懂,尤其是对于处理上述提到的二维数据结构遍历和元素两两组合等常见情况,程序员可以很直观地根据外层循环和内层循环的控制变量来理解代码是如何对数据进行处理的。
- 通用性强:它是一种非常通用的遍历方式,可以适用于多种数据结构和不同的应用场景,只要涉及到需要对多个层次的数据进行遍历或者组合操作,都可以考虑使用双层循环。
双层循环的缺点
-
时间复杂度高:在最常见的应用场景下,如本题中对数组进行遍历以找出所有元素两两组合的情况,双层循环的时间复杂度通常是 ,其中
n
是数据结构中元素的数量(如数组的长度)。这意味着当数据量较大时,程序的运行时间会显著增加,可能导致性能不佳。 -
代码可读性可能受影响:虽然在简单场景下双层循环逻辑清晰,但当内层循环和外层循环的嵌套逻辑较为复杂,或者在内层循环和外层循环中要执行大量复杂的操作时,代码可能会变得臃肿且难以理解,从而影响代码的可读性和可维护性。
双层循环是一种常用的编程技巧,在合适的场景下能很好地完成数据遍历和组合等操作,但也要注意其缺点,在数据量较大或对性能要求较高的场景下,可能需要考虑更优化的算法来替代双层循环的使用。