【华为OD机试真题】【2024年E卷】空栈压数-栈(C++/Java/Python)

分值:100

题目描述

向一个空栈压入正整数,每当压入一个整数时,执行以下规则(设: 栈顶至栈底整数依次编号为n1、n2...nx, n1为最新压入的整数)。

  1. 如果n1 = n2,则n1n2全部出栈,压入新数据m(m = 2 * n1)
  2. 如果n1 = n2 + ... + ny(y的范围为[3,x]),则n1、n2...ny全部出栈,压入新数据m(m = 2 * n1)。
  3. 如果上述规则都不满足,则不做操作
    如: 依次向栈压入6、1、2、3,当压入2时,栈顶至栈底依次为[2, 1, 6];当压入3时,3 = 2 + 13、2、1全部出栈,重新入栈整数6,此时栈顶至栈底依次为[6, 6]; 6 = 6,两个6全部出栈,压入12,最终栈中只剩个元素12
    向栈中输入一串数字,请输出应用此规则后栈中最终存留的数字。

输入描述:
使用单个空格隔开的正整数的字符串,如5 6 7 8,左边的数字先入栈。
输出描述:
最终栈中存留的元素值,元素值使用空格隔开,如8 7 6 5,栈顶数字在左边。

示例1
输入:
5 10 20 50 85 1
输出:
1 170
解释:
5 + 10 + 20 + 50 = 85,输入 85 时,5、10、20、50、85 全部出栈,入栈 170,最终依次出栈的数字为 1 和 170。
示例2
输入:
6 7 8 13 9
输出:
9 13 8 7 6
示例2
输入:
1 2 5 7 9 1 2 2
输出:
4 1 9 14 1

Tips:

  • 输入的正整数个数为 x,1<=x<=1000
  • 0 < n1, n2...ny < 1e5

思路

  • 结合 12 两条信息,可以等价于如果当前要进栈的数字num,如果跟后面连续k个数字之和相等的话,就把这些数字都出栈并且把2 * num入栈。
  • 为了快速遍历当前栈里面的元素,本题可以使用数组来模拟栈的操作。
  • 由于都是正整数,所以数字之和具有单调性。所以如果数据范围x > 1e5的话,可以使用前缀和+二分查找进行优化。本题数据范围较小,可以直接使用两层for循环暴力模拟得出答案。

复杂度分析

  • 时间复杂度: O(N2)O(N^2)O(N2),其中N为数字个数。
  • 空间复杂度: O(N)O(N)O(N),其中N为数字个数。

AC 代码

C++ 版

#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e3 + 5;
vector<int> split(string str, char point)
{
    vector<int> res;
    stringstream ss(str);
    string token;
    while (getline(ss, token, point))
    {
        // stoi 要求 C++ 11 以上
        res.push_back(stoi(token.c_str()));
    }
    return res;
}
int main()
{
    vector<int> s(MAX);
    int pos = 0; // pos 表示栈顶下一个位置
    string str;
    getline(cin, str);
    vector<int> seats = split(str, ' ');
    for (auto num : seats)
    {
        s[pos] = num;
        int cur = 0;
        // 计算 pos 之前的数字之和,如果恰好有连续的数字之和等于 num 的话,就合并然后入栈
        for (int i = pos - 1; i >= 0 && cur < num; i--)
        {
            cur += s[i];
            if (cur == num)
            {
                s[i] = num * 2;
                pos = i;
                break;
            }
        }
        pos++;
    }
    for (int i = pos - 1; i >= 0; i--)
    {
        cout << s[i] << " ";
    }
    return 0;
}

JAVA 版

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int MAX = 1005;
        int[] s = new int[MAX];
        int pos = 0;
        
        String str = scanner.nextLine();
        String[] parts = str.split(" ");
        int[] seats = new int[parts.length];
        
        for (int i = 0; i < parts.length; i++) {
            seats[i] = Integer.parseInt(parts[i]);
        }
        
        for (int num : seats) {
            s[pos] = num;
            int cur = 0;
            
            for (int i = pos - 1; i >= 0 && cur < num; i--) {
                cur += s[i];
                if (cur == num) {
                    s[i] = num * 2;
                    pos = i;
                    break;
                }
            }
            
            pos++;
        }
        
        for (int i = pos - 1; i >= 0; i--) {
            System.out.print(s[i] + " ");
        }
    }
}

Python 版

def split(string, point):
    return [int(x) for x in string.split(point)]

MAX = 1005
s = [0] * MAX
pos = 0

str = input()
seats = split(str, ' ')

for num in seats:
    s[pos] = num
    cur = 0
    
    for i in range(pos - 1, -1, -1):
        if cur < num:
            cur += s[i]
            if cur == num:
                s[i] = num * 2
                pos = i
                break
    
    pos += 1

for i in range(pos - 1, -1, -1):
    print(s[i], end=' ')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值