497 队列问题 | 豆包MarsCode AI刷题

101 阅读2分钟

问题描述

给定一个长度为 n 的序列a1​,a2​,…,an​,你可以选择删去其中最多 n−1 个数,得到一个新序列 b1,b2,…,bm​ (1≤m≤n),新序列保留原来的相对顺序。你的目标是删除某些数,使得新序列的第 i 个数 bi=i。现在需要求出最少删除多少个数才能得到这样的序列,如果无法得到,输出 −1。

例如,对于序列 [1, 4, 2, 3, 5],删除第 2 个和第 5 个元素后,可以得到序列 [1, 2, 3]

问题理解

  1. 删去至多n-1个数,说明最后满足题意的序列必须不为空。
  2. 新序列保留原来的相对顺序,删除元素后不能改变原来的相对顺序
  3. 题目关键是要让第 i 个数 bi = i,据此可以对原序列遍历,只要第 i 个数 bi ≠ i,则把当前位置元素删除,统计个数加一

解题思路

  1. 由于需要对每一位元素进行判断,固然要用到遍历
  2. 题目只要求统计删除元素个数,因此定义一个变量count记录删除元素个数
  3. 遍历时,判断每一位元素和序列编号是否一致,比如序列第一位必须为1,第二位必须为2,以此类推
  4. 当删除一个元素后,后面元素位置名义上需要向前移动一位,为了记录当前位置应该是哪一位,可以用一个变量currentNum记录遍历到当前元素应该是第几位,当删除元素时,count++, currentNum--,即本该是第 i 位的变为第i - 1位。如删除第2位,则第3位应变为第2位。
  5. 继续遍历之后位元素,直到判断完所有元素是否满足题意
  6. 若最后删除的元素超过 n - 1 ,则不满足题意,输出 -1
  7. 最后输出 count 就是题目所需的解

代码详解

public static int solution(int n, int[] a) {
        // 统计删除元素个数
        int count = 0;
        // 当前位应为第几位
        int currentNum = 1;
        for (int i = 0; i < a.length; i++) {
            // 当前元素不应该在当前位置,要删除当前元素
            if (currentNum != a[i]) {
                count++;
                currentNum--;
            }
            currentNum++;
        }
        if (count > n - 1) return -1;
        return count; // placeholder return
    }

复杂度计算

时间复杂度:O(n), n是题目给定数组的长度

空间复杂度:O(1)

总结

该思路设计巧妙在于,当判断完前面的元素是否符合题意之后,执行删除完无需重复判断前面的数字,前面的数字已经是满足等于序列号这个条件了,所以可以直接从删除位置下一位开始向后判断。