《数轴上的石子游戏》《数组长度缩减到1》《最低成本清空数组》

114 阅读4分钟

《数轴上的石子游戏》

题面

image.png

问题理解

题目要求我们通过最少的移动次数,使得三枚石子的位置连续。具体来说,就是将三个位置 a, b, c 调整为连续的三个整数。

数据结构选择

通过 vector<int> 来存储这三个位置,并通过 sort 函数对它们进行排序。

算法步骤

  1. 排序:首先对三个位置进行排序,使得 nums[0] <= nums[1] <= nums[2]

  2. 判断连续性

    • 如果 nums[0] + 1 == nums[1]nums[1] + 1 == nums[2],说明三个位置已经连续,不需要任何移动,返回 0
    • 如果 nums[0] + 1 == nums[1]nums[1] + 1 == nums[2],说明有一个位置已经连续,只需要移动一次即可,返回 1
    • 如果 nums[0] + 2 == nums[1]nums[1] + 2 == nums[2],说明有一个位置只差一个单位就可以连续,也只需要移动一次,返回 1
    • 其他情况,说明至少需要移动两次才能使三个位置连续,返回 2

具体实现

int solution(int a, int b, int c) {
    // 将三个位置存储到 vector 中并排序
    vector<int> nums = {a, b, c};
    sort(nums.begin(), nums.end());
    
    // 判断是否已经连续
    if (nums[0] + 1 == nums[1] && nums[1] + 1 == nums[2]) {
        return 0;
    } 
    // 判断是否只需要移动一次
    else if (nums[0] + 1 == nums[1] || nums[1] + 1 == nums[2] || 
             nums[0] + 2 == nums[1] || nums[1] + 2 == nums[2]) {
        return 1;
    } 
    // 其他情况,至少需要移动两次
    else {
        return 2;
    }
}

《数组长度缩减到1》

题面

image.png

问题理解

题目要求我们判断是否可以通过若干次操作将数组 A 缩减到长度为 1。每次操作可以选择一个索引 i,如果 A[i]A[i+1] 都小于 X,则可以将这两个元素移除,并在它们的位置插入它们的和。

数据结构选择

通过 std::stack 来处理数组元素。栈是一种后进先出(LIFO)的数据结构,适合用于处理需要反向操作的场景。

算法步骤

  1. 初始化栈:将数组 A 中的元素依次压入栈中。
  2. 合并操作:每次由栈中取出一个元素 cur,然后检查栈顶元素是否可以与 cur 合并(即两者之和小于 X)。如果可以,则合并并继续检查;否则,将 cur 压回栈中。
  3. 最终判断:如果栈中只剩下一个元素,则返回 1,表示可以缩减到长度为 1;否则返回 0

具体实现

int solution(int N, int X, std::vector<int>& A) {
    if(N == 1) {
        return 0;  // 如果数组长度为1,直接返回0(这里有争议,我个人其实更偏向于返回1)
    }
    std::stack<int> stk;
    for(int i : A) {
        stk.push(i);  // 将当前元素压入栈中
        int cur = stk.top();  // 取出栈顶元素
        stk.pop();  // 弹出栈顶元素
        while(!stk.empty() && cur + stk.top() < X) {
            // 如果栈非空且栈顶元素与cur的和小于X,则合并
            cur += stk.top();
            stk.pop();
        }
        stk.push(cur);  // 将合并后的元素压回栈中
    }
    int a = stk.top();  // 取出栈顶元素
    stk.pop();
    if(stk.empty()) {
        return 1;  // 如果栈为空,说明数组可以缩减到长度为1
    }
    int b = stk.top();  // 取出栈顶元素
    stk.pop();
    if(!stk.empty()) {
        return 0;  // 如果栈中还有元素,说明数组无法缩减到长度为1
    }
    return a < X && b < X;  // 检查最后两个元素是否都小于X
}

《最低成本清空数组》

题面

image.png

问题理解

题目要求我们通过一系列迭代操作将数组清空,每次迭代中必须删除K个值相同的元素。每次迭代的成本为 T * V,其中T是迭代的次数,V是被删除元素的值。目标是找到清空数组的最低成本。如果不可能清空数组,则返回-1

数据结构选择

通过std::vector来存储数组A,并通过std::sort对数组进行排序。排序的目的是为了更容易地找到相同值的元素,并进行批量删除。

算法步骤

  1. 排序:首先对数组A进行排序,这样相同值的元素会聚集在一起。
  2. 检查数组长度是否能被K整除:如果数组长度N不能被K整除,说明无法通过每次删除K个元素来清空数组,直接返回-1
  3. 迭代删除:由数组的末尾开始,每次删除K个元素。如果当前K个元素的值不相同,则返回-1,表示无法清空数组。否则,计算当前迭代的成本并累加到总成本中。

具体实现

int solution(int N, int K, std::vector<int> A) {
    int ret = 0;
    sort(A.begin(), A.end());
    if (N % K != 0) {
        return -1;
    }
    for (int i = N - 1; i >= 0; i -= K) {
        if (A[i] != A[i - K + 1]) {
            return -1;
        }
        ret += (N - i - 1 + K) / K * A[i];
    }
    return ret;
}