浪潮笔试 石头

题目描述:
沙滩按照线型摆放着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;
        

    }
}

你可能感兴趣的:(数据结构和算法)