【备战秋招】每日一题:2023.05.10-华为OD机试(第一题)-塔子哥的茶杯

为了更好的阅读体检,可以查看我的算法学习博客
在线评测链接:P1306

题目内容

有一个叫做塔子哥的人,他非常喜欢喝茶。他有 x x x 个奇怪的杯子,每个杯子都可以装入一个正整数。塔子哥决定将这些杯子中的个数字压入一个栈中,但他有些规矩:每次他要向栈中压入一个数字,如果这个数字与栈顶数字相同,他就会将这两个数字取出来相加,并且将它们的和的两倍压入栈中。另外,如果栈顶数字等于前面连续的 y y y 个数字的和( 2 2 2 ≤ \leq y y y ≤ \leq x x x),他也会将这 y y y 个数字取出来相加,并且将它们的和的两倍压入栈中。当然,如果以上两个规则都不满足,他就不会进行任何操作。现在,塔子哥将一组正整数依次压入栈中,请你告诉他最终栈中剩下的数字是什么。

输入描述

使用单个空格隔开的正整数的字符串,如" 5 5 5 6 6 6 7 7 7 8 8 8", 左边的数字先入栈。

正整数的范围为[ 1 1 1, 2 31 − 1 2^{31}-1 2311]

正整数个数的范围为[ 1 1 1, 1000 1000 1000]。

输出描述

最终栈中存留的元素值,元素值使用的单个空格隔开,如" 8 8 8 7 7 7 6 6 6 5 5 5", 从做至右依次为栈顶至栈底的数字。

样例1

输入

55 66 121 5 5

输出

10 242

解释:向栈压入 121 121 121 时, 55 55 55 + 66 66 66 = 121 121 121 ,数据合并后入栈 242 242 242 ,压入两个 5 5 5 时,合并为 10 10 10 ,最终栈顶至栈底的数字为 10 10 10 242 242 242 .

样例2

输入

7 5 8 9 3

输出

3 9 8 5 7

解释:无任何整数合并

思路:模拟栈

什么是

栈是一个先进后出的容器,你可以理解为一个只有一边能够打开的羽毛球筒,那我们想把最里面的羽毛球取出来,就得把所有羽毛球都取出来,这就是栈。

我们需要将给出的 n n n 个正整数逐一加入到栈中,但是在每次入栈时,如果我们发现有以下两种情况,就需要做出相应的操作:

  1. 当前数 x x x 和栈顶 y y y 是同一个数,那么我们需要取出栈顶数 y y y ,并将一个新的数 x + y x+y x+y 或者说是 2 ∗ x 2*x 2x 加入到栈中
  2. 当前数 x x x 和栈顶开始往下的任意个数( ≥ 2 \ge 2 2)的数的和相等,那么我们需要将所有这些数都取出来,并把一个新的数 2 ∗ x 2*x 2x 加入到栈中

由于正整数个数 n n n 的范围为[1,1000],因此直接模拟栈实现题目所要求的操作即可。

唯一需要注意的是,在将数字合并之后再次压入栈的同时,可能还会触发数字合并的操作,比如说:

当前栈中有3个数,分别为2,4,3。此时,我们需要将一个数3加入到栈中,我们先是触发了第一个情况,于是我们把3取出,得到了一个新的数 2 ∗ 3 = 6 2*3=6 23=6 ,并准备将6加入到栈中。这时栈里面有2个数分别为2,4,于是我们又触发了第二个条件,取出2和4,并得到了数字12。

最终,栈里面仅有一个数字,也就是12。

在最坏情况下,在每次压入栈时,都会遍历前面所有数字判断是否有数字(或者一串数字的和)与入栈数字相等(比如一个单调递减的序列),因此该方法的时间复杂度为: O ( N 2 ) O(N^2) O(N2)

类似题目推荐

代码

C++

#include <iostream>
#include <cstdio>
using namespace std;
#define ll long long

const int maxn=1e3+10;
ll stack[maxn];
int top;

int main(){
	ll x;
	while(scanf("%lld",&x)!=EOF){//读入数据 
		while(1){
		// 存在合并后压入栈再次合并的情况,因此循环判断是否有合并的情况 
			bool flag=false;
			ll tmp=0;
			for(int i=top;i&&top;--i){// 暴力查找是否和为x的数 
				tmp+=stack[i];
				if(tmp==x){// 存在一段和为x,合并,并更新栈 
					x=x+tmp;
					top=i-1;
					flag=true;
					break;
				}
			}
			if(flag==false) 
				break;
		}
		stack[++top]=x;
	}
	while(top){
		printf("%lld ",stack[top]);
		top--;
	}
	
	return 0;
}

python

maxn = 1010
stack = [0] * maxn
top = 0

while True:
    x = int(input())  # 读入数据
    if x == -1:
        break
    while True:
        flag = False
        tmp = 0
        for i in range(top, 0, -1):  # 暴力查找是否和为x的数
            tmp += stack[i]
            if tmp == x:  # 存在一段和为x,合并,并更新栈
                x = x + tmp
                top = i - 1
                flag = True
                break
        if not flag:
            break
    top += 1
    stack[top] = x

while top:
    print(stack[top], end=" ")
    top -= 1

Java

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        final int maxn = 1010;
        long[] stack = new long[maxn];
        int top = 0;

        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLong()) {
            long x = scanner.nextLong(); // 读入数据
            while (true) {
                boolean flag = false;
                long tmp = 0;
                for (int i = top; i > 0; i--) { // 暴力查找是否和为x的数
                    tmp += stack[i];
                    if (tmp == x) { // 存在一段和为x,合并,并更新栈
                        x = x + tmp;
                        top = i - 1;
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    break;
                }
            }
            top++;
            stack[top] = x;
        }
        scanner.close();

        while (top > 0) {
            System.out.print(stack[top] + " ");
            top--;
        }
    }
}

Go

package main

import "fmt"

const maxn = 1010

func main() {
	var stack [maxn]int64 // 栈数组
	top := 0 // 栈顶指针

	var x int64
	for {
		_, err := fmt.Scanf("%d", &x) // 读入数据
		if err != nil {
			break
		}
		for {
			flag := false // 标记是否存在合并的情况
			var tmp int64 // 临时变量存储和
			for i := top; i > 0; i-- { // 暴力查找是否和为x的数
				tmp += stack[i]
				if tmp == x { // 存在一段和为x,合并,并更新栈
					x = x + tmp
					top = i - 1
					flag = true
					break
				}
			}
			if !flag {
				break
			}
		}
		top++
		stack[top] = x
	}

	for top > 0 {
		fmt.Printf("%d ", stack[top])
		top--
	}
}

Js

const maxn = 1010; // 最大数组长度
let stack = new Array(maxn); // 栈数组
let top = 0; // 栈顶指针

function main() {
    let input = require('readline-sync'); // 导入readline-sync模块,用于读取用户输入
    
    while (true) {
        let x = parseInt(input.question()); // 读入数据
        if (isNaN(x)) { // 判断输入是否为数字,若不是则退出循环
            break;
        }
        while (true) {
            let flag = false; // 标记是否存在合并的情况
            let tmp = 0; // 临时变量存储和
            for (let i = top; i > 0; i--) { // 暴力查找是否和为x的数
                tmp += stack[i];
                if (tmp === x) { // 存在一段和为x,合并,并更新栈
                    x = x + tmp;
                    top = i - 1;
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                break;
            }
        }
        top++;
        stack[top] = x;
    }

    while (top > 0) {
        process.stdout.write(stack[top] + " "); // 输出栈顶元素并空格分隔
        top--;
    }
}

main(); // 调用主函数执行

题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值