原题目链接:合唱队_牛客题霸_牛客网
题目总结:就是给一个数组,通过删除一部分元素使其满足最大数左边是递增数组,右边是递减数组,得出一个最长的数组。
解题思路:
1.先依次算出数组(data)中每个元素左边的最大递增元素长度,放置一个数组(left)中。
1.1 第一个元素左边没有元素,最大递增元素长度记为1(此元素自己)
1.2 第二个元素如果大于第一个元素,则最大递增元素长度记为2(此元素自己和第一个元素),如果小于等于第一个元素,则最大递增元素长度记为1(此元素自己)
1.3 依此类推,第n个元素的最大递增元素长度为此元素前面第一个(从此数往前数第一个)小于此元素的数的最大递增元素长度+1。例如:【数组为[1,2,3,4,5,4,5,6,8,3,6,7],则第6(数组下标,从0开始计)个元素(5)的最大递增元素长度为此元素前面第一个(从此数往前数第一个)小于此元素的数(第5个元素4)的最大递增元素长度加1,而第5个元素(4)的最大递增元素长度为此元素前面第一个小于此元素的数(第2个元素3)的最大递增元素长度加1为4】,此步骤即为动态规划
2. 参照第1步,计算依次算出数组(data)中每个元素右边的最大递减元素长度,放置一个数组(right)中。
3. 将第1步(left)和第2步(right)中相同下标的元素相加,得到一个新的数组(resutLengthArrays),数组中的值即为此原始数据(data)中此下标对于的值作为结果(result)中的最大数时,数组(result)的最长长度,取出result中的最大值(maxIndex)(如果存在最大值相同,任取一个即可)。
4.然后将左边需要被删除的数置位0,将右边需要被删除的数置位0,将不需要被删除的数依次放到新的集合中即可得到结果
import java.util.ArrayList;
import java.util.List;
/**
* https://www.nowcoder.com/practice/6d9d69e3898f45169a441632b325c7b4
*
* @date 2023/4/30 18:40
**/
public class Choir {
public static List<Integer> sort(int[] data) {
int length = data.length;
//存储每个数左边小于其的数的个数
int[] left = new int[length];
//计算每个位置左侧的最长递增
for (int i = 0; i < length; i++) {
left[i] = 1;
for (int j = 0; j < i; j++) {
if (data[i] > data[j]) {
left[i] = Math.max(left[j] + 1, left[i]);
}
}
}
//存储每个数右边小于其的数的个数
int[] right = new int[length];
//计算每个位置右侧的最长递减
for (int i = length - 1; i >= 0; i--) {
right[i] = 1;
for (int j = length - 1; j > i; j--) {
if (data[i] > data[j]) {
right[i] = Math.max(right[i], right[j] + 1);
}
}
}
// 记录每个位置的值
int[] resultLengthArrays = new int[length];
for (int i = 0; i < length; i++) {
//因为left和right都包含了元素本身,位置i计算了两次,所以需要-1
resultLengthArrays[i] = left[i] + right[i] - 1;
}
//找到满足要求的最大的数组长度
int max = 1;
//找到满足要求的最大数的下标
int maxIndex = 0;
for (int i = 0; i < length; i++) {
if (resultLengthArrays[i] > max) {
max = resultLengthArrays[i];
maxIndex = i;
}
}
//将左边需要被删除的数置位0,从maxIndex往前依次保留等于当前递增长度减一的数,因为递增长度肯定是逐次加1的,这里是递增长度,不是源数据
for (int i = maxIndex - 1, j = left[maxIndex]; i >= 0; i--) {
if (left[i] == j - 1) {
j--;
} else {
left[i] = 0;
}
}
//将右边需要被删除的数置位0,这里同上
for (int i = maxIndex + 1, j = right[maxIndex]; i < right.length; i++) {
if (right[i] == j - 1) {
j--;
} else {
right[i] = 0;
}
}
List<Integer> result = new ArrayList<>();
//将左边的数加入到集合中
for (int i = 0; i < maxIndex; i++) {
if (left[i] != 0) {
result.add(data[i]);
}
}
//将右边的数加入到集合中
for (int i = maxIndex; i < right.length; i++) {
if (right[i] != 0) {
result.add(data[i]);
}
}
return result;
}
}