#P3299. 第2题-变量生命周期计算
-
1000ms
Tried: 325
Accepted: 88
Difficulty: 7
所属公司 :
华为
时间 :2025年6月25日-暑期实习
-
算法标签>栈
第2题-变量生命周期计算
题目描述
在Rust语言中,变量的生命周期与其作用域绑定,退出作用域时自动销毁。我们用一个简化模型来模拟这一过程:
-
“{” 和 “}” 表示新开和结束一个作用域;
-
每行要么是
let name:在当前作用域声明变量name,drop name:在当前作用域手动销毁变量name。
-
离开一个作用域时,若有未被
$drop$的变量,则自动按“后声明先销毁”顺序销毁。
出错情况:
1. 销毁了一个未在同一作用域中声明的变量;
2. 已声明的变量被 drop 超过一次。
输出要求:按销毁顺序依次输出变量名,用空格分隔;若出错,则输出已成功销毁的变量,后跟一个空格和字符串 "Error",然后终止。
思路
-
使用一个栈来管理作用域,每个作用域对应一个栈帧,栈帧内部维护一个按声明顺序的列表。
-
维护一个全局哈希表,记录每个变量所属的栈帧层级以及是否已被销毁。
-
逐行处理输入:
-
遇到
{,压入新的空栈帧; -
遇到
},弹出当前栈帧,按逆序自动销毁其中所有未被drop的变量; -
遇到
let name,将$name$加入当前栈帧尾部,并在哈希表中标注层级及“未销毁”; -
遇到
drop name,检查哈希表:- 若不存在或层级不匹配,则报错;
- 若已销毁,则报错;
- 否则标记为已销毁,输出该变量。
-
-
若中途报错,停止处理并输出
"Error";否则最终完成所有行后输出结果。
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N; // 读取总行数 N
string line;
vector<vector<string>> scopeStack; // 作用域栈
unordered_map<string, pair<int,bool>> info; // 变量 -> (层级, 已销毁)
vector<string> output; // 记录销毁顺序
bool error = false;
getline(cin, line); // 吸收行末
for (int i = 0; i < N; i++) {
getline(cin, line);
// 去除前导空格
int pos = line.find_first_not_of(' ');
if (pos == string::npos) continue;
line = line.substr(pos);
if (line == "{") {
// 新作用域
scopeStack.emplace_back();
}
else if (line == "}") {
// 结束当前作用域,自动销毁未 drop 的变量
int lvl = scopeStack.size() - 1;
auto &frame = scopeStack.back();
for (int k = frame.size() - 1; k >= 0; k--) {
const string &v = frame[k];
if (!info[v].second) {
output.push_back(v);
info[v].second = true;
}
}
scopeStack.pop_back();
}
else if (line.rfind("let ", 0) == 0) {
// let 操作
string var = line.substr(4);
int lvl = scopeStack.size() - 1;
scopeStack.back().push_back(var);
info[var] = {lvl, false};
}
else if (line.rfind("drop ", 0) == 0) {
// drop 操作
string var = line.substr(5);
if (!info.count(var) || info[var].first != (int)scopeStack.size() - 1) {
// 未声明或不在本层
error = true;
} else if (info[var].second) {
// 重复 drop
error = true;
} else {
// 合法 drop
output.push_back(var);
info[var].second = true;
}
}
if (error) {
break;
}
}
// 输出结果
for (auto &v : output) {
cout << v << ' ';
}
if (error) {
cout << "Error";
}
return 0;
}
Python
import sys
def main():
N = int(sys.stdin.readline().strip()) # 读取总行数 N
scope_stack = [] # 作用域栈,每层是变量列表
info = {} # 变量 -> (层级, 已销毁)
output = []
error = False
for _ in range(N):
line = sys.stdin.readline().lstrip()
if line.startswith('{'):
scope_stack.append([])
elif line.startswith('}'):
lvl = len(scope_stack) - 1
frame = scope_stack.pop()
# 自动销毁
for var in reversed(frame):
if not info[var][1]:
output.append(var)
info[var] = (lvl, True)
elif line.startswith('let '):
var = line.split()[1]
lvl = len(scope_stack) - 1
scope_stack[-1].append(var)
info[var] = (lvl, False)
elif line.startswith('drop '):
var = line.split()[1]
if var not in info or info[var][0] != len(scope_stack) - 1:
error = True
elif info[var][1]:
error = True
else:
output.append(var)
info[var] = (info[var][0], True)
if error:
break
# 打印输出
print(' '.join(output), end='')
if error:
print('Error')
if __name__ == '__main__':
main()
Java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine().trim()); // 读取总行数 N
List<List<String>> scopeStack = new ArrayList<>(); // 作用域栈
Map<String, Pair> info = new HashMap<>(); // 变量 -> (层级, 已销毁)
List<String> output = new ArrayList<>();
boolean error = false;
for (int i = 0; i < N; i++) {
String line = br.readLine().replaceAll("^\\s+", "");
if (line.equals("{")) {
scopeStack.add(new ArrayList<>());
} else if (line.equals("}")) {
int lvl = scopeStack.size() - 1;
List<String> frame = scopeStack.remove(lvl);
// 自动销毁
for (int k = frame.size() - 1; k >= 0; k--) {
String var = frame.get(k);
Pair p = info.get(var);
if (!p.destroyed) {
output.add(var);
p.destroyed = true;
}
}
} else if (line.startsWith("let ")) {
String var = line.substring(4);
int lvl = scopeStack.size() - 1;
scopeStack.get(lvl).add(var);
info.put(var, new Pair(lvl, false));
} else if (line.startsWith("drop ")) {
String var = line.substring(5);
if (!info.containsKey(var) || info.get(var).level != scopeStack.size() - 1) {
error = true;
} else if (info.get(var).destroyed) {
error = true;
} else {
output.add(var);
info.get(var).destroyed = true;
}
}
if (error) break;
}
// 输出结果
for (String v : output) {
System.out.print(v + " ");
}
if (error) {
System.out.print("Error");
}
}
// 存储变量信息的辅助类
static class Pair {
int level;
boolean destroyed;
Pair(int level, boolean destroyed) {
this.level = level;
this.destroyed = destroyed;
}
}
}
题目内容
在 Rust 语言中,一个变量的生命周期是与其变量的作用域绑定的,变量离开作用域时被自动销毁。
这里给出一个简单的模型;一对大括号为一个生命周期,除了括号之外,每一行包含以下两个操作之一:
let {var_ name} drop {var _ name}
其中:let 表示声明一个变量,{var_ name} 为变量名;drop 表示手动销毁一个变量,销毁的对象为变量名 {var_name} 。
其它规则:离开一个作用域时,如果有变量没有被drop显式销毁,则自动销毁,顺序规则是后声明的先销毁。
出错情况:
1.销毁了一个没有声明的变量。
2.一个已经声明的变量被手动 drop 超过一次。
输入描述
第一行为一个数字 N ,表示后面待输入代码的行数。
其中:5<=N<=15000 。
{ 独占一行
} 独占一行
let 和变量名之间只有一个空格
drop 和变量名之间只有一个空格
变量名只包含大小写字母,长度为 [1,32]
输入约束:
1.全局每一行 let 声明变量的变量名都不相同。
2.用例中不会出现 drop 非同一作用域变量(包括父作用域)的情况。
3.除输入的第一行为行数,输入的第二行一定会是 '{' ,最后一行一定是'}' :即一定会显式声明一个最外层作用域。
4.每一行输入的行头可能有 0 个或者多个前导空格,let/drop 与变量名之间只有一个空格。
5.不会出现括号不成对匹配、变量名不符号要求等输入异常的场景,编码时不需要考虑括输入不正确的场景。
输出描述
输出各变量的销毁顺序,以一个空格分隔
如果发生出错的情况,则将出错前成功释放的变量全部按要求打印出来之后,再接一个空格和一个固定字符串 “Error”,然后中止输出。
样例1
输入
6
{
let a
let b
let c
drop b
}
输出
b c a
说明
按行说明:
待输入的总代码行数为 6
新增第一个作用域
第一个作用域声明变量 a
第一个作用域声明变量 b
第一个作用域声明变量 c
显式销毁 b
离开第一个作用域,按声明反序,销毁 ca (因为 b 已经显式销毁)
样例2
输入
9
{
let a
let b
{
let c
}
drop b
drop d
}
输出
c b Error
说明
按行说明:
待输入的总代码行数为 9
新增第一个作用域
第一个作用域声明变量 a
第一个作用域声明变量 b
新增第二个作用域
第二个作用域声明变量 c
离开第二个作用域,按声明反序,自动销毁 c
显式销毁 b
显式销毁 d ,但是 d 在其所属的第一个作用域中还没有声明,报错退出
样例3
输入
12
{
let a
let b
{
let c
{
let d
let f
}
}
drop b
}
输出
f d c b a
说明
按行说明:
待输入的总代码行数为 12
新增第一个作用域
第一个作用域声明变量 a
第一个作用域声明变量 b
新增第二个作用域
第二个作用域 声明变量 c
新增第三个作用域
第三个作用域 声明变量 d
第三个作用域 声明变量 f
离开第三个作用域,按声明反序,销毁 f d
离开第二个作用域,按声明反序,销毁 c
显式销毁变量 b
离开第一个作用,按声明反序,销毁 a (因为b已经显式销毁)
样例4
输入
7
{
let a
{
drop a
}
}
输出
Error
说明
按行说明:
待输入的总代码行数为 7
新增第一个作用域
第一个作用域声明变量 a
新增第二个作用域
drop 变量 a ,但是 a 非本作用域变量(为其父作用域变量),出错。