首页 > 试题广场 >

撤销与恢复

[编程题]撤销与恢复
  • 热度指数:3074 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 128M,其他语言256M
  • 算法知识视频讲解
撤销/恢复操作具有广泛的用途,比如word文档中输入一个单词,可以点撤销,然后可以再恢复。
编程实现如下功能:  从标准输入读取到一个字符串,字符串可包含0个或多个单词,单词以空格或者tab分隔; 如果遇到 "undo" 字符串,表示"撤销"操作,前一个字符串被撤销掉; 如果遇到"redo"字符串,表示恢复刚才撤销掉的字符串.
例如:   输入字符串 "hello undo redo world.",  对字符串中的 undo 和 redo 处理后, 最终输出的结果为 "hello world."

输入描述:
一行字符串: 包含0个或多个单词,单词以空格或者tab分隔


输出描述:
一行字符串: 由0个或多个单词组成,单词以空格分隔
示例1

输入

hello undo redo world.

输出

hello world.
先初始化两个栈stack和redo,然后利用双栈求解。遍历词表:
  1. 遇到普通词就压入stack,并清空redo栈,因为此时写入了一个新词,再往前的词已经找不回来了;
  2. 遇到undo就从stack中弹栈至redo;
  3. 遇到redo就从redo中弹栈至stack。
最终stack中的词就是最后保留下来的词
commands = input().strip().split(" ")
stack, redo = [], []
for cmd in commands:
    if cmd == "undo":
        if stack:
            redo.append(stack.pop())
    elif cmd == "redo":
        if redo:
            stack.append(redo.pop())
    else:
        redo.clear()
        stack.append(cmd)
print(" ".join(stack))
发表于 2022-01-08 20:08:09 回复(5)
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        List<String> li = new LinkedList(Arrays.asList(sc.nextLine().split(" ")));
        Deque<String> dq = new LinkedList<String>();
        for(int i = 0;i<li.size();i++){
            if(li.get(i).equals("undo")&&i!=0) {
                dq.push(li.get(i-1));
                li.remove(i);
                li.remove(i-1);
                i-=2;
                continue;
            }
            if(li.get(i).equals("redo")) {
                if(!dq.isEmpty()) {
                    li.remove(i);
                    li.add(i,dq.pop());
                }
            }
        }
        
        System.out.println(String.join(" ", li));
        sc.close();
    }
}

发表于 2022-01-22 21:09:06 回复(3)

先初始化两个栈stack和redo,然后利用双栈求解。遍历词表:
  1. 遇到普通词就压入stack,并清空redo栈,因为此时写入了一个新词,再往前的词已经找不回来了;
  2. 遇到undo就从stack中弹栈至redo;
  3. 遇到redo就从redo中弹栈至stack。
package com.tuling.partone;


import java.util.*;

public class Test {

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        String str=scanner.nextLine();
        Stack stack=ctrlZ(str);
        System.out.println(String.join(" ", stack));
    }

    private static Stack ctrlZ(String str) {
        Stack<String> stack = new Stack<String>();
        Stack<String> redoStack = new Stack<String>();
        List<String> list = new ArrayList<>(Arrays.asList(str.replace("\t", " ").split(" ")));
        for (int i = 0; i < list.size(); i++) {
            if ("undo".equals(list.get(i))){
                if (!stack.empty()){
                    redoStack.push(stack.pop());
                }
            }else if("redo".equals(list.get(i))){
                if(!redoStack.empty()){
                    stack.push(redoStack.pop());
                }
            }else{
                redoStack.clear();
                stack.push(list.get(i));
            }

        }
        return stack;
    }
}

编辑于 2022-05-09 15:18:22 回复(0)
function changeStr( str ) {
    // write code here
    var result = ''
    var splitStr = str.split(' ')
    var undoStr = []
    for (let i =0; i < splitStr.length; i++){
        // 发现撤销
        if (splitStr[i] === 'undo') {
                undoStr.push(splitStr[i - 1])
                splitStr.splice(i - 1, 2)
                i -= 2
        // 发现还原
        } else if (splitStr[i] === 'redo') {
            if (undoStr.length == 0) {
                splitStr.splice(i, 1)
                i -= 1
            } else {
                splitStr.splice(i, 1)
                splitStr.splice(i, 0, undoStr.pop())
            }
        // 正常字符,则清空undo
        } else {
            undoStr = []
        }
    }
    splitStr.map((item) => {
        result += ` ${item}`
    })
    return result.substr(1, result.length - 1)
}
print(changeStr(readline()))
貌似没人发JS的,献丑一下,代码比较笨,欢迎指正
发表于 2022-02-23 19:30:53 回复(2)
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()){
            ctrlZ(sc.nextLine());
        }
    }

    private static void ctrlZ(String str) {

        List<String> list = new ArrayList<>(Arrays.asList(str.replace("\t", " ").split(" ")));

        Deque<String> deque = new LinkedList<>();

        for (int i=0;i<list.size();i++){
            if("undo".equals(list.get(i))){
                list.remove(i--);
                if(i>=0){
                    deque.push(list.get(i));
                    list.remove(i--);
                }
            }else if("redo".equals(list.get(i))){
                list.remove(i);
                if(!deque.isEmpty()){
                    list.add(i++,deque.pop());
                }
                i--;
            }else{
                deque.clear();
            }
        }
        System.out.println(String.join(" ",list));
    }
}
提交一直是差一个测试点没通过,后来发现是恢复操作添加元素时需要把位置加1,因为下面为了不漏过redo后面的单词,所以有个i--,所以位置不加1的话就会再次访问到添加的这个单词,这样就会触发else条件,把原先的deque清空(本不该清空),就会导致不正确的结果出现。

发表于 2022-03-30 19:07:43 回复(0)
请指教
public class UndoRedo {
    public static void main(String[] args) throws InterruptedException {
        // 创建存储对外显示的字符串的栈集合 usefulWords
        Stack<String> usefulWords = new Stack<> ();
        // 创建储存删除的字符串的栈集合 uselessWords
        Stack<String> uselessWords = new Stack<> ();
        // 创建scanner对象获取用户输入的字符串
        Scanner scanner = new Scanner (System.in);
        // 创建输入的死循环,可暂用 不输入 表示结束输入
        while (true) {
            // 友好提示
            System.out.print ("请输入:");
            String input= scanner.nextLine ();
            // 不输入表示结束循环
            if (input == null || input.equals ("")) {
                System.out.println ("感谢使用,Bye");
                return;
            }
            // 切割字符串
            String[] inputWords = input.split (" ");
            for (String inputWord : inputWords) {
                // 判断输入的字符串值 undo redo  其他三种情况
                if ("undo".equals (inputWord)) {
                    // usefulWords 非空则移除 usefulWords 栈顶的元素,添加到 uselessWords 集合
                    if (!usefulWords.empty ()) {
                        uselessWords.push (usefulWords.pop ());
                    }
                } else if ("redo".equals (inputWord)) {
                    // uselessWords 非空则移除 uselessWords 栈顶的元素,添加到 usefulWords 集合
                    if (!uselessWords.empty ()) {
                        usefulWords.push (uselessWords.pop ());
                    }
                } else {
                    // 把输入的字符串添加到 usefulWords 集合中,加空格为排版~~
                    usefulWords.push (inputWord + " ");
                }
            }

            // 显示输入的数据
            System.out.print ("目前文章:");
            usefulWords.forEach (System.err::print);

            // 为显示效果,睡 0.1 秒再执行下一次循环
            Thread.sleep (100);
            // 添加空格排版~~~
            System.out.println ();
        }
    }
}

编辑于 2022-01-22 23:02:07 回复(1)
#include <iostream> #include <sstream> #include <string> #include <vector> using namespace std; int main() { // 读取用户输入的一行命令,存储在input字符串中 string input; getline(cin, input); // 将输入的字符串按空格分割,存储在commands向量中 vector<string> commands; stringstream ss(input); string cmd; while (ss >> cmd) { commands.push_back(cmd); } // 用于模拟操作栈,存储执行的命令 vector<string> stack; // 用于存储被撤销的命令,以便重做 vector<string> redo; // 遍历输入的命令 for (const auto& cmd : commands) { // 如果命令是"undo" if (cmd == "undo") { // 如果操作栈不为空 if (!stack.empty()) { // 将操作栈顶的命令移到重做栈中 redo.push_back(stack.back()); // 从操作栈中弹出该命令 stack.pop_back(); } } // 如果命令是"redo" else if (cmd == "redo") { // 如果重做栈不为空 if (!redo.empty()) { // 将重做栈顶的命令移回操作栈 stack.push_back(redo.back()); // 从重做栈中弹出该命令 redo.pop_back(); } } // 如果是其他命令 else { // 清空重做栈 redo.clear(); // 将命令添加到操作栈 stack.push_back(cmd); } } // 输出操作栈中的命令,以空格分隔 for (const auto& word : stack) { cout << word << " "; } cout << endl; return 0; }</string></string></string></vector></string></sstream></iostream>
发表于 2024-10-23 17:24:49 回复(0)

redo只有遇到undo才有意义,undo如果没被redo抵消,则会撤销在redo出现前的字符串

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] arr = scanner.nextLine().split(" ");
        Stack stack = new Stack();
        StringBuilder builder = new StringBuilder();
        for(String s:arr){
            // 遇到普通字符入栈
            // 遇到undo,暂时放入栈中
            // 遇到redo,碰到undo则抵消
            if(s.equals("redo")){
                if(stack.peek().equals("undo")){
                    stack.pop();
                }
            }else{
                stack.push(s);
            }
        }
        while(!stack.isEmpty()){
            String s = stack.pop();
            if(s.equals("undo")){
                stack.pop();
            }else{
                builder.insert(0," "+s);
            }
        }
        System.out.println(builder.substring(1).toString());
    }
}
发表于 2024-08-30 11:27:57 回复(0)
提供一个JavaScript代码啦~~~
代码量炒鸡低~~~成功AC
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void async function () {
    // Write your code here
    while(line = await readline()){
        let tokens = line.split(' ');
        let curr = 0;
        let str = [];
        for (let i = 0; i < tokens.length; i++) {
            if (tokens[i] !== "undo" && tokens[i] !== "redo") {
                str.push(tokens[i]);
                curr ++;
            } else if (i + 1 < tokens.length && tokens[i] === "undo" && tokens[i + 1] === "redo") {
                i ++;
            } else if (tokens[i] === "undo") {
                str.splice(curr - 1, 1);
            }
        }
        
        console.log(str.join(" "));
    }
}()


发表于 2023-03-12 23:33:16 回复(0)

测试用例通不过的问题在于undo与redo一定要在一起才能生效,且有可能出现叠加状态。通过l类似于栈的用法,连续undo时++,遇到redo--,遇到普通字符清零。然后就是基本的栈用法了

#include <bits/stdc++.h>
using namespace std;
int main(){
    string tmp;
    stack<string> undoer;
    vector<string> anss;
    int l=0;
    while(cin>>tmp){
        if(tmp=="undo"){
            if(anss.size()){             
                undoer.push(anss.back());
                anss.pop_back();
                l++;
            }
        }else
        if(tmp=="redo"){
            if(l>0&&undoer.size()){
                anss.push_back(undoer.top());
                undoer.pop();
                l--;
            }
        }else{
            anss.push_back(tmp);
            l=0;
        }
    }
    for(int i=0;i<anss.size();i++){
        if(i!=anss.size()-1){
            cout<<anss[i]<<" ";
        }else
            cout<<anss[i]<<endl;
    }
    return 0;
}
发表于 2022-10-08 11:01:51 回复(0)
import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        String s1 = "";
        ArrayList<String> strings = new ArrayList<>();
        ArrayList<String> strings2 = new ArrayList<>();
        String[] strings1 = s.split(" ");
        for (int i = 0; i < strings1.length; i++) {
            strings.add(i, strings1[i]);
        }
        String beiyong = "";

        for (int i = 0; i < strings.size(); i++) {
            if("undo".equals(strings.get(i))){
                beiyong = strings2.get(strings2.size()-1);
                strings2.remove(strings2.size()-1);
            }else if("redo".equals(strings.get(i))){
                strings.add(beiyong);
                beiyong = "";
            }else {
                strings2.add(strings.get(i));
                beiyong = "";
            }
        }
        for (int i = 0; i < strings2.size(); i++) {
            s1 = strings2.get(i)+" "+s1;
        }
        System.out.println(s1);
    }
}
发表于 2022-08-28 16:28:42 回复(0)
请问各位大佬为什么我这总有一个用例过不去
import java.util.LinkedList;
import java.util.Scanner;

/**
 * @author dokey
 * @Title:
 * @Package
 * @Description:
 * @date 2022/8/2510:33
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        String[] str = s.replace("/t"," ").split(" ");
        LinkedList<String> res = new LinkedList<>();
        LinkedList<String> del = new LinkedList<>();
        for (String i : str){
            if (i.equals("undo")){
                if (!res.isEmpty()){
                    String temp = res.removeLast();
                    del.addLast(temp);
                }

            }else if (i.equals("redo")){
                if (!del.isEmpty()){
                    String temp = del.removeLast();
                    res.addLast(temp);
                }

            }else {
                res.addLast(i);
            }
        }
        while (!res.isEmpty()){
            if (res.size() == 1){
                System.out.print(res.removeFirst());
            }else {
                System.out.print(res.removeFirst() + " ");
            }
        }

    }
}


发表于 2022-08-25 11:28:44 回复(0)
#include<iostream>
#include<queue>
usingnamespacestd;
intmain()
{
    string word;
    deque<string> text_queue,undo_queue;
    while(cin>>word)
    {
        if(word=="undo")
        {
            if(!text_queue.empty())
            {
                undo_queue.push_back(text_queue.back());
                text_queue.pop_back();
            }
        }
        elseif(word=="redo")
        {
            if(!undo_queue.empty())
            {
                text_queue.push_back(undo_queue.back());
                undo_queue.pop_back();
            }
        }
        else{
            text_queue.push_back(word);
            undo_queue=deque<string>();
        }
    }
    for(inti=0;i<text_queue.size();++i)
    {
        cout<<text_queue[i]<<" ";
    }
}
发表于 2022-08-21 16:23:46 回复(0)

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] s = sc.nextLine().split(" ");
        Deque<String> stack = new LinkedList<>();
        Deque<String> res = new LinkedList<>();
        for (String value : s) {
            if (value.equals("undo")) {
                if (!res.isEmpty()) {
                    stack.push(res.pop());
                }
                continue;
            }
            if (value.equals("redo")) {
                if (!stack.isEmpty()) {
                    res.push(stack.pop());
                }
                continue;
            }
            res.push(value);
            stack.clear();
        }
        StringBuilder sb = new StringBuilder();
        while (!res.isEmpty()) {
            sb.insert(0, res.pop() + " ");
        }
        System.out.println(sb);
        sc.close();
    }
}

发表于 2022-08-20 13:04:20 回复(0)
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	str, _ := reader.ReadString('\n')
	str = str[:len(str)-1]
	strs := strings.Split(str, " ")
	ans := []string{}
	start, end := 0, 0
	m := map[string]int{}
	for i := 0; i < len(strs); i++ {
		if strs[i] == "redo" || strs[i] == "undo" {
			end = i
			for strs[i] == "redo" || strs[i] == "undo" {
				if strs[i] == "redo" && m["undo"] > 0 {
					m["undo"]--
				}
				if strs[i] == "undo" {
					m["undo"]++
				}
				i++
			}
			end -= m["undo"]
			ans = append(ans, strs[start:end]...)
			start = i
			end = i
		}
		if i == len(strs)-1 {
			ans = append(ans, strs[start:]...)
		}
	}
	s := ""
	for i := 0; i < len(ans); i++ {
		s += ans[i] + " "
	}
	fmt.Println(s)
}

发表于 2022-08-12 22:54:33 回复(0)
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String seg;
        String line = sc.nextLine();
        if (line.contains(" ")) {
            seg = " ";
        } else {
            seg = "\t";
        }
        String[] ss = line.split(seg);
        sc.close();
        Stack<String> stack = new Stack<>();
        Stack<String> undo = new Stack<>();
        
        for (String s : ss) {
            if ("redo".equals(s)) {
                if (!undo.isEmpty()) {
                    stack.push(undo.pop());
                }
            } else if ("undo".equals(s)) {
                if (!stack.isEmpty()) {
                    undo.push(stack.pop());
                }
            } else {
                undo.clear();
                stack.push(s);
            }
        }
        
        StringBuilder sb = new StringBuilder();
        while (!stack.isEmpty()) {
            sb.insert(0, stack.pop()).insert(0, " ");
        }
        if (sb.length() > 0) 
            System.out.println(sb.substring(1));
    }
}

发表于 2022-07-02 21:38:04 回复(0)
package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    var input string
    reader := bufio.NewReader(os.Stdin)
    input, _ = reader.ReadString('\n')
    sp := strings.Split(input, " ")
    length := len(sp)
    sp[length-1] = sp[length-1][:len(sp[length-1])-1]
    iArr := make([]int, len(sp)+1)
    index := 0
    wordIn := false
    for i := 0; i < length; i++ {
        if sp[i] == "undo" {
            index--
            if index < 0 {
                index = 0
            }
            wordIn = false
        } else if sp[i] == "redo" {
            if wordIn == true {
                continue
            }
            index++
        } else {
            wordIn = true
            iArr[index] = i
            index++
        }
    }
    sArr := make([]string, 0)
    for i := 0; i < index; i++ {
        sArr = append(sArr, sp[iArr[i]])
    }
    fmt.Println(strings.Join(sArr, " "))
}
发表于 2022-06-02 19:35:56 回复(0)
#include<bits/stdc++.h>
using namespace std;

int main() {
    vector<string> undo_queue, words;
    string s;
    while (cin >> s) {
        char ch = getchar();
//遇到undo时,将words的最后一个单词放进undo_queue中,然后弹出这个单词
        if (s == "undo") {
            if (!words.empty()) {
                undo_queue.push_back(words.back());
                words.pop_back();
            }
        }
//遇到redo时,将undo_queue中的最后一个词取出放回到words中,并弹出这个词
        else if (s == "redo") {
            if (!undo_queue.empty()) {
                words.push_back(undo_queue.back());
                undo_queue.pop_back();
            }
        }
//遇到普通词直接放进words中,并且要清空undo_queue,因为插入的新的词以后undo_queue里的数据已经不是最新的了
        else {
            words.push_back(s);
            undo_queue = vector<string>();
        }
        if (ch == '\n')
            break;
    }
    for (auto word : words) {
        cout << word << " ";
    }
    return 0;
}


发表于 2022-05-08 12:58:58 回复(1)
题目确定没有问题吗
发表于 2022-04-19 20:30:54 回复(0)
package main
import(
    "os"  
    "bufio"
    "fmt"
    "strings"
)

func RedoUndoStr(str string) string{
    strList := strings.Split(str," ")
    stack := make([]string,0)
    redo := make([]string,0)
    for _,val:=range strList{
        if val=="redo"{
            if len(redo)>0{
                stack=append(stack, redo[len(redo)-1])
                redo=redo[:len(redo)-1]
            }
        }else if val=="undo"{
            if len(stack)>0{
                redo=append(redo, stack[len(stack)-1])
                stack=stack[:len(stack)-1]
            }
        }else{
            redo=redo[:0]
            stack=append(stack, val)
        }
    }
    return strings.Join(stack," ")
}
func main(){
    reader:=bufio.NewReader(os.Stdin)
    str,_:=reader.ReadString('\n')
    fmt.Println(RedoUndoStr(str))
}

编辑于 2022-03-22 09:09:09 回复(0)

问题信息

上传者:小小
难度:
23条回答 3997浏览

热门推荐

通过挑战的用户

撤销与恢复