题目描述:
沙滩按照线型摆放着n个大小不一的球形石头,已知第i个石头的半径为ri,且不存在两个石头有相同的半
径。为了使石头的摆放更加美观,现要求摆放的石头的半径从左往右依次递增。因此,需要对一些石头
进行移动,每次操作可以选择一个石头,并把它放在剩下n−1个石头在最左边或最右边。问最少需要操
作多少次才能将这n个石头的半径变成升序?
样例输入
5
4 1 2 5 3
样例输出
2
思路
1. 求出最长递增且连续的子序列的长度。举个例子,nums = {1, 5, 9, 7, 3},排序后的数组sorted_nums = {1, 3, 5, 7, 9}。【1 5 9】是一个递增序列,但不是连续的,因为根据sorted_nums,5和9中间隔着7,所以它不是连续的。对于nums,其最长递增其连续子序列为【1,3】或者【5,7】。
2. 保持最长递增连续的子序列不动,移动其他元素。故最少的操作数为n-最长递增且连续子序列的长度
code
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; ++i) nums[i] = sc.nextInt();
int[] arr = Arrays.copyOf(nums, nums.length);
Arrays.sort(arr);
HashMap<Integer, Integer> next = new HashMap<>();
// 构建从小到大的关系
for (int i = 0; i < n-1; ++i)
next.put(arr[i], arr[i+1]);
next.put(arr[n-1], Integer.MAX_VALUE);
HashMap<Integer, Integer> dp = new HashMap<>();
// 用于记忆化
dp.put(nums[n-1], 1);
int maxlen = 1;
for (int i = n-2; i >= 0; --i){
if (dp.containsKey(next.get(nums[i]))){
dp.put(nums[i], dp.get(next.get(nums[i])) + 1);
}
else{
dp.put(nums[i], 1);
}
maxlen = Math.max(maxlen, dp.get(nums[i]));
}
return n - maxlen;
}
}