Tag Archives: 堆栈

LeetCode Evaluate Reverse Polish Notation

150. Evaluate Reverse Polish Notation

Evaluate the value of an arithmetic expression in Reverse Polish Notation.

Valid operators are +-*/. Each operand may be an integer or another expression.

Note:

  • Division between two integers should truncate toward zero.
  • The given RPN expression is always valid. That means the expression would always evaluate to a result and there won’t be any divide by zero operation.

Example 1:

Input: ["2", "1", "+", "3", "*"]
Output: 9
Explanation: ((2 + 1) * 3) = 9

Example 2:

Input: ["4", "13", "5", "/", "+"]
Output: 6
Explanation: (4 + (13 / 5)) = 6

Example 3:

Input: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
Output: 22
Explanation: 
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

本题要对一个逆波兰表达式求值。简单题,借助一个堆栈,遇到数字压栈,遇到操作符,把栈顶两个元素弹栈并进行运算。需要注意的是,假设先后弹出来的两个元素是v1,v2,则后续的所有操作都应该是v2 op v1,不要搞错了。 完整代码如下:

class Solution {
public:
    int evalRPN(vector<string>& tokens)
    {
        stack<int> expression;
        for (size_t i = 0; i < tokens.size(); ++i) {
            if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
                int v1 = expression.top();
                expression.pop();
                int v2 = expression.top();
                expression.pop();
                if (tokens[i] == "+")
                    expression.push(v2 + v1);
                else if (tokens[i] == "-")
                    expression.push(v2 – v1);
                else if (tokens[i] == "*")
                    expression.push(v2 * v1);
                else if (tokens[i] == "/")
                    expression.push(v2 / v1);
            }
            else
                expression.push(atoi(tokens[i].c_str()));
        }
        return expression.top();
    }
};

本代码提交AC,用时9MS。

LeetCode Binary Search Tree Iterator

Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST.

Calling next() will return the next smallest number in the BST.

Example:

BSTIterator iterator = new BSTIterator(root);
iterator.next();    // return 3
iterator.next();    // return 7
iterator.hasNext(); // return true
iterator.next();    // return 9
iterator.hasNext(); // return true
iterator.next();    // return 15
iterator.hasNext(); // return true
iterator.next();    // return 20
iterator.hasNext(); // return false

Note:

  • next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is the height of the tree.
  • You may assume that next() call will always be valid, that is, there will be at least a next smallest number in the BST when next() is called.

本题要求设计一个二叉搜索树的迭代器,迭代的输出当前树中最小值,并且要求next和hasNext是O(1)时间复杂度和O(h)空间复杂度,h为树的高度。 因为二叉搜索树的中序遍历是递增有序的序列,所以如果没有O(h)空间复杂度限制,则可以提前保存中序遍历结果,然后实现对数组的迭代器。但是这样的空间复杂度就是O(sizeof(tree)),不符合题意。 立马想到树的中序遍历的非递归实现,我们可以借助一个堆栈,先只把树的根和最左边的数压栈,这样栈顶元素就是树的最下角元素,也就是最小值。每调用一次next,返回当前栈顶元素,同时把栈顶元素的右孩子及右孩子的所有最左边的节点压栈。hasNext就好办,直接返回堆栈是否为空。 这样堆栈中最多会保存树高个数的节点,所以是O(h)的空间复杂度。完整代码如下:

class BSTIterator {
private:
    stack<TreeNode*> tree;
    void putAllLeft(TreeNode* root, stack<TreeNode*>& tree)
    {
        while (root != NULL) {
            tree.push(root);
            root = root->left;
        }
    }
public:
    BSTIterator(TreeNode* root) { putAllLeft(root, tree); } /** @return whether we have a next smallest number */
    bool hasNext() { return !tree.empty(); } /** @return the next smallest number */
    int next()
    {
        TreeNode* top = tree.top();
        tree.pop();
        putAllLeft(top->right, tree);
        return top->val;
    }
};

本代码提交AC,用时19MS。

LeetCode Insert Delete GetRandom O(1) – Duplicates allowed

LeetCode Insert Delete GetRandom O(1) – Duplicates allowed Design a data structure that supports all following operations in average O(1) time. Note: Duplicate elements are allowed.

  1. insert(val): Inserts an item val to the collection.
  2. remove(val): Removes an item val from the collection if present.
  3. getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.
Example:
// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection();
// Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1);
// Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1);
// Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2);
// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom();
// Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1);
// getRandom should return 1 and 2 both equally likely.
collection.getRandom();

这一题在LeetCode Insert Delete GetRandom O(1)的基础上,增加了有重复元素的约束。还是用数组+Hash实现,但是Hash表中不再只是存储单个元素的下标了,而是存储所有相同元素的下标的集合,采用最大堆(priority_queue)来存储相同元素的下标集合。 插入时,数值插入到数组末尾,下标插入到hash表中该数值对应的最大堆中,如果堆原来为空的话,说明这是第一次插入该数值。删除时,取出val在数组中的最大下标(priority_queue.top()即为堆中最大值),如果不是数组末尾,则和数组末尾的数值交换,同时更新原数组末尾数值的下标最大堆,最后删掉数组末尾的数。产生随机数同样好办,直接rand下标。 完整代码如下: [cpp] class RandomizedCollection { private: unordered_map<int, priority_queue<int>> hash; vector<int> nums; public: /** Initialize your data structure here. */ RandomizedCollection() { } /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */ bool insert(int val) { hash[val].push(nums.size()); nums.push_back(val); return hash[val].size() == 1; } /** Removes a value from the collection. Returns true if the collection contained the specified element. */ bool remove(int val) { if (hash[val].empty())return false; int pos = hash[val].top(); hash[val].pop(); if (pos != nums.size() – 1) { nums[pos] = nums[nums.size() – 1]; hash[nums[pos]].pop(); hash[nums[pos]].push(pos); } nums.pop_back(); return true; } /** Get a random element from the collection. */ int getRandom() { return nums[rand() % nums.size()]; } }; [/cpp] 本代码提交AC,用时85MS。 但是为什么要用最大堆来存储相同数值的下标集合呢,而且最大堆的插入和删除效率不是O(1)的呀,难道是因为相同的数比较少?所以每个数值的下标堆很小,所以插入和删除的复杂度近似为O(1)? 那么能否用数组来存储相同数值的下标集合呢,即用unordered_map<int, vector> hash,答案是不可以。举例如下: 假设经过了6次插入之后,数组为[10,10,20,20,30,30],此时不同数值的下标集合为:
  • 10:[0,1]
  • 20:[2,3]
  • 30:[4,5]
此时删除10,则会把第二个10删掉,同时把末尾的30放到第二个10的位置,数组变为[10,30,20,20,30],此时下标集合为:
  • 10:[0]
  • 20:[2,3]
  • 30:[4,1]
如果此时再次删除10,则会把第一个10删掉,同时把末尾的30放到第一个10的位置,数组变为[30,30,20,20],但是此时的下标集合变为了:
  • 10:[]
  • 20:[2,3]
  • 30:[4,0]
即30的下标集合出现了错误,因为存储下标集合的数据结构是vector,O(1)的删除只能是pop_back(),但是这样并不能保证删掉最大的下标,本来这次我们是要删掉最大的下标4的,但是结果却删了0,依然保存了已不存在的下标4。所以用最大堆的目的就是为了每次删除都删掉最大的下标。 但是最大堆的插入和删除毕竟不是O(1),再次使用Hash存储下标才是真正的O(1)做法,即用unordered_map> hash,这样的话,在上面的例子中,我可以用O(1)的时间删除下标4。 [cpp] class RandomizedCollection { private: unordered_map<int, unordered_set<int>> hash; vector<int> nums; public: /** Initialize your data structure here. */ RandomizedCollection() { } /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */ bool insert(int val) { hash[val].insert(nums.size()); nums.push_back(val); return hash[val].size() == 1; } /** Removes a value from the collection. Returns true if the collection contained the specified element. */ bool remove(int val) { if (hash[val].empty())return false; int pos = *hash[val].begin(); hash[val].erase(pos); if (pos != nums.size() – 1) { nums[pos] = nums[nums.size() – 1]; hash[nums[pos]].erase(nums.size() – 1); hash[nums[pos]].insert(pos); } nums.pop_back(); return true; } /** Get a random element from the collection. */ int getRandom() { return nums[rand() % nums.size()]; } }; [/cpp] 本代码提交AC,用时79MS。]]>

LeetCode Decode String

LeetCode Decode String Given an encoded string, return it’s decoded string. The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer. You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc. Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won’t be input like 3a or 2[4]. Examples:

s = "3[a]2[bc]", return "aaabcbc".
s = "3[a2[c][/c]]", return "accaccacc".
s = "2[abc]3[cd]ef", return "abcabccdcdcdef".

题意:要求把加密的字符串解密。加密规则是重复k次的子串str写成k[str],方括号可能会有嵌套。 所以我们需要解析加密字符串,把方括号中的内容提取出来,然后复制k份,因为有嵌套,面对括号匹配问题,堆栈是最好的解决办法。我们不断把字符串压栈,直到遇到],从栈中不断弹出,直到遇到[,期间的字符串就是我们要重复的str,然后弹出k,重复k次,把重复的字符串再次压栈。如此不断循环,最后只要把栈中的字符串连接起来就好了。 完整代码如下: [cpp] class Solution { public: string decodeString(string s) { stack<string> stk; for (int i = 0; i < s.size(); ++i) { if (s[i] != ‘]’)stk.push(string(1, s[i])); else { string cur = ""; while (stk.top() != "[") { // stk不可能为空 cur = stk.top() + cur; stk.pop(); } stk.pop(); string cnt = ""; while (!stk.empty() && isdigit(stk.top()[0])) { // 此处stk可能为空 cnt = stk.top() + cnt; stk.pop(); } int n = atoi(cnt.c_str()); string repeated = ""; while (n–)repeated += cur; stk.push(repeated); } } string ans = ""; while (!stk.empty()) { ans = stk.top() + ans; stk.pop(); } return ans; } }; [/cpp] 本代码提交AC,用时3MS。]]>

LeetCode Simplify Path

71. Simplify Path

Given an absolute path for a file (Unix-style), simplify it. Or in other words, convert it to the canonical path.

In a UNIX-style file system, a period . refers to the current directory. Furthermore, a double period .. moves the directory up a level.

Note that the returned canonical path must always begin with a slash /, and there must be only a single slash / between two directory names. The last directory name (if it exists) must not end with a trailing /. Also, the canonical path must be the shortest string representing the absolute path.

Example 1:

Input: "/home/"
Output: "/home"
Explanation: Note that there is no trailing slash after the last directory name.

Example 2:

Input: "/../"
Output: "/"
Explanation: Going one level up from the root directory is a no-op, as the root level is the highest level you can go.

Example 3:

Input: "/home//foo/"
Output: "/home/foo"
Explanation: In the canonical path, multiple consecutive slashes are replaced by a single one.

Example 4:

Input: "/a/./b/../../c/"
Output: "/c"

Example 5:

Input: "/a/../../b/../c//.//"
Output: "/c"

Example 6:

Input: "/a//b////c/d//././/.."
Output: "/a/b/c"

简化Unix路径字符串。使用栈数据结构,扫描字符串,获取/之前的字符串,如果是一点.则保持当前路径,什么也不做;如果是两点..则弹栈,否则把字符串压栈。 需要注意的是/../,/.,/…等情况,三个点应该认为一个合法的路径字符串,虽然在Windows上并不合法。所以我们在进行算法之前,不管原始字符串末尾是否包含/,我们都在末尾添加上斜杠/,以便后续统一处理。 扫描完一次字符串之后,把栈内字符串依次弹出并组合成一个简化的路径。 完整代码如下:

class Solution {
public:
    string simplifyPath(string path)
    {
        path += "/";
        stack<string> sPath;
        string p1 = "";
        for (int i = 0; i < path.size(); i++) {
            if (path[i] == ‘/’) {
                if (p1 == "" || p1 == ".") {
                }
                else if (p1 == "..") {
                    if (!sPath.empty())
                        sPath.pop();
                }
                else {
                    sPath.push(p1);
                }
                p1 = "";
            }
            else
                p1 += path[i];
        }
        if (sPath.empty())
            return "/";
        string ans = "";
        while (!sPath.empty()) {
            ans = "/" + sPath.top() + ans;
            sPath.pop();
        }
        return ans;
    }
};

本代码提交AC,用时6MS。

二刷。更简洁代码:

class Solution {
public:
	string simplifyPath(string path) {
		stack<string> stk;
		int n = path.size();
		int i = 0, j = 0;
		while (i < n) {
			while (i < n&&path[i] == '/')++i;
			if (i >= n)break;
			j = i + 1;
			while (j < n&&path[j] != '/')++j;
			string name = path.substr(i, j - i);
			if (name == ".." && !stk.empty())stk.pop();
			if (name != "."&&name != "..")stk.push(name);
			i = j;
		}
		string ans = "";
		while (!stk.empty()) {
			ans = "/" + stk.top() + ans;
			stk.pop();
		}
		if (ans == "")return "/";
		else return ans;
	}
};

本代码提交AC,用时8MS。

LeetCode Longest Valid Parentheses

32. Longest Valid Parentheses

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

Example 1:

Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"

Example 2:

Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"

此题要求一个括号字符串中最长的合法的括号串的长度。 遇到括号问题,想当然的用栈来解决,可以尝试每一个以'(‘开头的字符串,用栈求出其最长合法括号串的长度,然后求全局最大值,如下:

class Solution {
public:
    int longestValidParentheses(string s)
    {
        int n = s.size(), maxval = 0;
        for (int i = 0; i < n; i++) { if (s[i] == ‘(‘) {
                stack<char> sc;
                sc.push(s[i]);
                int cur = 0;
                for (int j = i + 1; j < n; j++) {
                    char t = sc.top();
                    if (s[j] == ‘)’)
                        { if (t == ‘(‘) {
                                sc.pop();
                                cur++; } else break;
                        }
                    sc.push(s[j]);
                }
                if (cur > maxval)
                    maxval = cur; }
        }
        return maxval * 2;
    }
};

但是这个算法是$O(n^2)$的,TLE。

后来看题解,居然有$O(n)$的解法,厉害,如下:

class Solution {
public:
	int longestValidParentheses(string s)
	{
		int n = s.size(), maxval = 0, start = -1; // start初始化为-1
		stack<int> si;
		for (int i = 0; i < n; i++) {
			if (s[i] == '(') {
				si.push(i); //左括号无条件压栈 
			} else { //右括号不压栈
				if (si.empty()) {
					start = i; //以右括号作为新的起点
				} else {
					si.pop();
					if (si.empty()) // ()()() or (()())
						maxval = max(maxval, i - start);
					else // (() 用当前栈顶索引作为起点
						maxval = max(maxval, i - si.top());
				}
			}
		}
		return maxval;
	}
};

本算法提交AC,用时12MS。

它也是用堆栈,但是堆栈里存的不是括号,而是括号的索引。左括号无条件压栈,右括号不压栈,只是作为计算括号对的长度的起点(其实起点应该是右括号索引+1,但是计算长度的时候用右括号索引更方便)。

所以栈里面只有左括号,当右括号来了,且栈为空时,说明之前已经配对完了,要开始新的配对,所以设置新的起点。

如果栈不为空,则pop。如果pop完之后栈为空,也说明配对完成,可以更新最佳长度;如果pop完之后栈里还有左括号,则是(((()这种类型,左括号更多,则匹配的起点应该是栈顶的索引,而不是之前设置的右括号索引+1,如下:

(((() ^ ^

二刷。比较容易理解的是动态规划的方法。设dp[i]表示以字符i结尾的最长合法括号串的长度,则所有左括号对应的dp[i]都等于0,因为合法的括号串都是以右括号结尾的。

如果s[i]==’)’,有两种情况。第一种情况是s[i-1]='(‘,则s[i]和s[i-1]配对,所以dp[i]=dp[i-2]+2。第二种情况是s[i-1]也=’)’,则s[i]无法和s[i-1]配对,但是如果向前跨过s[i-1]对应的合法字符串后有左括号出现,则s[i]有望作为一个外围的右大括号配对成功,如下图所示,最右边的是第s[i]=’)’,向前跨过了(xxx),和前一个左括号配对成功。这种情况下,dp[i]=dp[i-1]+2,又因为配对的左括号前面还有可能是合法的括号串,所以还要加上dp[i-dp[i-1]-1-1]。

xxx((xxxx))

完整代码如下:

class Solution {
public:
	int longestValidParentheses(string s) {
		int n = s.size();
		vector<int> dp(n, 0);
		int ans = 0;
		for (int i = 0; i < n; ++i) {
			if (s[i] == ')') {
				if (i > 0 && s[i - 1] == '(') {
					dp[i] += 2;
					if (i >= 2)dp[i] += dp[i - 2];
				}
				else if (i > 0 && s[i - 1] == ')') {
					int left = i - dp[i - 1] - 1;
					if (left >= 0 && s[left] == '(') {
						dp[i] = dp[i - 1] + 2;
						if (left > 0)dp[i] += dp[left - 1];
					}
				}
			}
			ans = max(ans, dp[i]);
		}
		return ans;
	}
};

本代码提交AC,用时4MS。

至于用栈的方法,是这样的:栈中只插入左括号的下标,以便来了右括号后,把配对的左括号弹出,剩下栈顶左括号下标作为之前弹出的合法括号串的起始位置。如果栈顶为空,且来了右括号,则这个右括号肯定配对失败,所以也把它的下标入栈,用来充当后续合法括号串的起始位置。

更简洁易懂的代码如下:

class Solution {
public:
	int longestValidParentheses(string s) {
		int n = s.size();
		int ans = 0;
		stack<int> stk;
		stk.push(-1);
		for (int i = 0; i < n; ++i) {
			if (s[i] == '(') {
				stk.push(i);
			}
			else {
				if (!stk.empty())stk.pop();
				if (stk.empty()) {
					stk.push(i);
				}
				else {
					ans = max(ans, i - stk.top());
				}
			}
		}
		return ans;
	}
};

本代码提交AC,用时4MS。

LeetCode Valid Parentheses

20. Valid Parentheses

Given a string containing just the characters '('')''{''}''[' and ']', determine if the input string is valid.

An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.
  2. Open brackets must be closed in the correct order.

Note that an empty string is also considered valid.

Example 1:

Input: "()"
Output: true

Example 2:

Input: "()[]{}"
Output: true

Example 3:

Input: "(]"
Output: false

Example 4:

Input: "([)]"
Output: false

Example 5:

Input: "{[]}"
Output: true

判断一个带括号的字符串是否合法,直接用栈,水题,代码如下。

class Solution {
public:
    bool isValid(string s)
    {
        stack<char> pars;
        for (int i = 0; i < s.size(); i++) {
            if (pars.empty()) {
                pars.push(s[i]);
                continue;
            }
            char t = pars.top();
            if ((t == ‘(‘&& s[i] == ‘)’) || (t == ‘{ ‘&& s[i] == ‘ }’) || (t == ‘[‘&& s[i] == ‘]’))
                pars.pop();
            else
                pars.push(s[i]);
        }
        return pars.empty();
    }
};

本代码提交AC,用时0MS。

POJ 1068-Parencodings

POJ 1068-Parencodings Parencodings Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 20210 Accepted: 12196 Description Let S = s1 s2…s2n be a well-formed string of parentheses. S can be encoded in two different ways: q By an integer sequence P = p1 p2…pn where pi is the number of left parentheses before the ith right parenthesis in S (P-sequence). q By an integer sequence W = w1 w2…wn where for each right parenthesis, say a in S, we associate an integer which is the number of right parentheses counting from the matched left parenthesis of a up to a. (W-sequence). Following is an example of the above encodings: S (((()()()))) P-sequence 4 5 6666 W-sequence 1 1 1456 Write a program to convert P-sequence of a well-formed string to the W-sequence of the same string. Input The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case is an integer n (1 <= n <= 20), and the second line is the P-sequence of a well-formed string. It contains n positive integers, separated with blanks, representing the P-sequence. Output The output file consists of exactly t lines corresponding to test cases. For each test case, the output line should contain n integers describing the W-sequence of the string corresponding to its given P-sequence. Sample Input 2 6 4 5 6 6 6 6 9 4 6 6 6 6 8 9 9 9 Sample Output 1 1 1 4 5 6 1 1 2 4 5 1 1 3 9 Source Tehran 2001


简单题。给一个括号字符串的P序列,要求算出其W序列。 直接计算即可,首先根据P序列还原出该括号字符串,因为P序列的每一个数字是对应右括号的,所以这个数字就表示这个右括号左边有多少个左括号,通过一个while循环就可以还原出原始括号字符串。 得到原始括号字符串之后,就可以计算W序列了。W序列的每一个数字也是对应右括号的,它表示从“和该右括号匹配的左括号”的位置到“该右括号”的位置一共有多少个右括号。这就要求我们知道每一个右括号匹配的左括号的位置,用一个堆栈可以简单求出。 求除了右括号及其匹配的左括号的位置后,就可以遍历括号字符串计算出期间共有多少个右括号了。 求解思路清晰之后,可以快速写出完整代码: [cpp] #include<iostream> #include<string> #include<vector> #include<stack> using namespace std; typedef struct PAR//括号结构 { char c;//左括号或右括号 int pos;//该字符的下标 }; //根据P-sequence还原出括号字符串 string get_parentheses(vector<int>& p) { string rs=""; vector<int>::iterator it=p.begin(); int i=0; while(it!=p.end()) { while(i!=(*it)) { rs+='(‘; i++; } rs+=’)’; it++; } return rs; } //根据括号字符串paren得到W-sequence void get_w(vector<int>& w,string paren) { int len=paren.size(); stack<PAR> s_p; PAR par; vector<int> right_pos,left_pos;//分别记录某个右括号对应左括号的位置 for(int i=0;i<len;i++) { if(paren[i]=='(‘)//如果是左括号,入栈 { par.c=paren[i]; par.pos=i; s_p.push(par); } else//右括号,出栈,配对 { par=s_p.top(); s_p.pop(); right_pos.push_back(i); left_pos.push_back(par.pos); } } vector<int>::iterator it_r=right_pos.begin(); vector<int>::iterator it_l=left_pos.begin(); while(it_r!=right_pos.end())//计算W-sequence { int num=0; for(int i=*it_l;i<=*it_r;i++) { if(paren[i]==’)’) num++; } w.push_back(num); it_r++; it_l++; } } int main() { int t,n; cin>>t; while(t–) { cin>>n; vector<int> p;//P-sequence int tmp; string parentheses; while(n–) { cin>>tmp; p.push_back(tmp); } parentheses=get_parentheses(p); vector<int> w;//W-sequence get_w(w,parentheses); vector<int>::iterator it=w.begin(); while(it!=w.end()) { cout<<*it<<" "; it++; } cout<<endl; } return 0; } [/cpp] 本代码提交AC,用时0MS,内存764K。]]>

POJ 1028-Web Navigation

POJ 1028-Web Navigation Web Navigation Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 29660 Accepted: 13249 Description Standard web browsers contain features to move backward and forward among the pages recently visited. One way to implement these features is to use two stacks to keep track of the pages that can be reached by moving backward and forward. In this problem, you are asked to implement this. The following commands need to be supported: BACK: Push the current page on the top of the forward stack. Pop the page from the top of the backward stack, making it the new current page. If the backward stack is empty, the command is ignored. FORWARD: Push the current page on the top of the backward stack. Pop the page from the top of the forward stack, making it the new current page. If the forward stack is empty, the command is ignored. VISIT : Push the current page on the top of the backward stack, and make the URL specified the new current page. The forward stack is emptied. QUIT: Quit the browser. Assume that the browser initially loads the web page at the URL http://www.acm.org/ Input Input is a sequence of commands. The command keywords BACK, FORWARD, VISIT, and QUIT are all in uppercase. URLs have no whitespace and have at most 70 characters. You may assume that no problem instance requires more than 100 elements in each stack at any time. The end of input is indicated by the QUIT command. Output For each command other than QUIT, print the URL of the current page after the command is executed if the command is not ignored. Otherwise, print “Ignored”. The output for each command should be printed on its own line. No output is produced for the QUIT command. Sample Input VISIT http://acm.ashland.edu/ VISIT http://acm.baylor.edu/acmicpc/ BACK BACK BACK FORWARD VISIT http://www.ibm.com/ BACK BACK FORWARD FORWARD FORWARD QUIT Sample Output http://acm.ashland.edu/ http://acm.baylor.edu/acmicpc/ http://acm.ashland.edu/ http://www.acm.org/ Ignored http://acm.ashland.edu/ http://www.ibm.com/ http://acm.ashland.edu/ http://www.acm.org/ http://acm.ashland.edu/ http://www.ibm.com/ Ignored Source East Central North America 2001


水题一个。使用STL自带stack快速解决。有一个小细节需要注意:
BACK: Push the current page on the top of the forward stack. Pop the page from the top of the backward stack, making it the new current page. If the backward stack is empty, the command is ignored. FORWARD: Push the current page on the top of the backward stack. Pop the page from the top of the forward stack, making it the new current page. If the forward stack is empty, the command is ignored.
如果栈为空,则这个命令被忽略。被忽略的意思是就当没出现这个命令,自然也就不需要执行前半部分的操作了。
BACK: Push the current page on the top of the forward stack. FORWARD: Push the current page on the top of the backward stack.
完整代码如下: [cpp] #include<iostream> #include<stack> #include<string> using namespace std; int main() { //freopen("input.txt","r",stdin); string current_url="http://www.acm.org/"; stack<string> forward_url,backward_url; string command; while(cin>>command&&command!="QUIT") { if(command=="VISIT") { backward_url.push(current_url); cin>>current_url; cout<<current_url<<endl; while(!forward_url.empty()) { forward_url.pop(); } } else if(command=="BACK") { //forward_url.push(current_url);//If the backward stack is empty, the command is ignored忽略的话,这一句也不能执行 if(!backward_url.empty()) { forward_url.push(current_url); current_url=backward_url.top(); backward_url.pop(); cout<<current_url<<endl; } else { cout<<"Ignored"<<endl; } } else if(command=="FORWARD") { //backward_url.push(current_url); if(!forward_url.empty()) { backward_url.push(current_url); current_url=forward_url.top(); forward_url.pop(); cout<<current_url<<endl; } else { cout<<"Ignored"<<endl; } } } return 0; } [/cpp] 代码提交AC,用时0MS,内存200K。]]>