合唱队问题

原题目链接:合唱队_牛客题霸_牛客网

题目总结:就是给一个数组,通过删除一部分元素使其满足最大数左边是递增数组,右边是递减数组,得出一个最长的数组。

解题思路:

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;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值