1、栈的基础使用

1、给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true
示例 2:

输入: "()[]{}"
输出: true
示例 3:

输入: "(]"
输出: false
示例 4:

输入: "([)]"
输出: false
示例 5:

输入: "{[]}"
输出: true
这道题是众多公司面试题:
class Solution {
public:
    bool isValid(string s) {
        stack<char> stack;
        for(int i = 0; i< s.size(); i++){
            if(s[i] == '(' || s[i] == '{' || s[i] == '[')
                stack.push(s[i]);
            else{
                if(stack.size() == 0)
                    return false;
                char c = stack.top();
                stack.pop();
                char match;
                if(s[i] == ')')
                    match = '(';
                else if(s[i] == ']')
                    match = '[';
                else
                    match = '{';
                
                if(c != match)
                    return false;
            }
        }
        if(stack.size() != 0)
            return false;
        return true;
    }
};
2、逆波兰表达式(后缀表达式求值)
从左向右扫描,遇到数字压栈,遇到操作符,弹出栈顶的两个元素,先弹出的元素在右边,后弹出来的在左边,进行计算后,将结果压栈,再往后扫描,直到扫描结束,输出栈顶元素,即为最终结果
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> stack;
        int i = 0;
        while(i<tokens.size()){
            if(tokens[i]!="+" && tokens[i]!="-" && tokens[i]!="*" && tokens[i]!="/"){
                stack.push(stoi(tokens[i]));
            }
            else{
                int x,y;
                x = stack.top();
                stack.pop();
                y = stack.top();
                stack.pop();
                if(tokens[i] == "+")
                    stack.push(y+x);
                else if(tokens[i] == "-")
                    stack.push(y-x);
                else if(tokens[i] == "*")
                    stack.push(y*x);
                else
                    stack.push(y/x);
            }
            i++;
        }
        int res = stack.top();
        return res;
    }
};

2、栈和递归的紧密关系

1、二叉树中的算法

 给定一个二叉树,返回它的 前序 遍历。

1.1 这里模仿系统中的栈使用非递归的方式来实现
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

struct Command{
    string s;//定义的命令:go,print
    TreeNode * node;
    Command(string s,Treenode *node):s(s),node(node){}//构造函数
};

class Solution{
public:
vector<int> preorderTraversal(TreeNode* root) {
    vector<int> res;
    if(root == NULL)
        return res;
        
    stack<Command> stack;
    stack.push(Command("go",root));
    while(!stack.empty()){
        Command command = stack.top();
        stack.pop();
        if(command.s == "print")
            res.push_back(command.node->val);
        else{
            assert(command.s == "go");
            if(command.node->right)
                stack.push(Command("go",command.node->right));
            if(command.node->left)
                stack.push(Command("go",command.node->left));
            stack.push(Command("print",command.node));
        }
    }
    return res;
    }
};
1.2 递归
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        helper(root,res);
        return res;
    }
    void helper(TreeNode* root,vector<int>& res){
        if(root == NULL) 
                    return;
        res.push_back(root->val);
        helper(root->left,res);
        helper(root->right,res);
    }
};
1.3 迭代
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> sk;
        vector<int> res;
        while(root||sk.size()){
            while(root){
                sk.push(root);
                res.push_back(root->val);
                root=root->left;
            }
            root=sk.top();
                        sk.pop();
            root=root->right;
        }
        return res;
    }
};
2、二叉树中序遍历

递归:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        inorder(root,res);
        return res;
    }

    void inorder(TreeNode *root,vector<int>& res){
        if(root == NULL)
            return;
        inorder(root->left,res);
        res.push_back(root->val);
        inorder(root->right,res);
    }
};

非递归:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> stack;
        while(root || stack.size()){
            while(root){
                stack.push(root);
                root = root->left;
            }
            if(stack.size()){
                root = stack.top();
                stack.pop();
                res.push_back(root->val);
                root = root->right;
            }
        }
        return res;
       
    }
};
3、二叉树后序遍历

递归:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        postorder(root,res);
        return res;
    }
    void postorder(TreeNode *root,vector<int>& res){
        if(root ==NULL)
            return;
        postorder(root->left,res);
        postorder(root->right,res);
        res.push_back(root->val);
    }
};


非递归:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> stack,result;
        vector<int> res;
        if(root == NULL)
            return res;
        stack.push(root);
        while(stack.size()){
            root = stack.top();
            stack.pop();
            result.push(root);
            if(root->left)
                stack.push(root->left);
            if(root->right)
                stack.push(root->right);
        }
        while(result.size()){
            root = result.top();
            result.pop();
            res.push_back(root->val);
        }
        return res;
    }
};

3、队列

1、二叉树的层次遍历

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(root == NULL)
            return res;
        queue<pair<TreeNode*,int>> q;
        q.push(make_pair(root,0));
        while(!q.empty()){
            TreeNode *node = q.front().first;
            int level = q.front().second;
            q.pop();
            if(level == res.size())
                res.push_back(vector<int>());
            res[level].push_back(node->val);
            if(node->left)
                q.push(make_pair(node->left,level+1));
            if(node->right)
                q.push(make_pair(node->right,level+1));
        }
        return res;
    }
};
2、二叉树的锯齿形遍历
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

例如:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回锯齿形层次遍历如下:

[
  [3],
  [20,9],
  [15,7]
]




3.2 BFS(广度优先遍历)和图的最短路径

 1、给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例 1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.
示例 2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.

可以使用动态规划的方法来实现
class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1);
        for (int i = 1; i <= n; i++) {
            dp[i] = i;
            for (int j = 1; j * j <= i; j++) 
                dp[i] = min(dp[i], dp[i - j * j] + 1);
        }
        return dp[n];
    }
};

127.126


3.3 优先队列(底层实现:堆)

1、给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]
说明:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

   1.首先扫描一边数组并统计频率,排序找到前k个出现频率最高的元素
   2.维护一个含有k个元素的优先队列。如果遍历到的元素比队列中的最小频率的元素的频率高,则取出队列中最小频率的元素,将新的元素入队。最终,队列中剩下的,就是前k个出现频率最高的元素。
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
       map<int,int> freq;//第一个是元素,第二个是出现的频率
       
       //统计每个元素出现的频率
       for(int i =0;i<nums.size();i++)
            freq[nums[i]] ++;
        //扫描freq,维护当前出现频率最高的k个元素
        //在优先队列中,按照频率排序,所以数据对是(频率,元素)的形式
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>> > pq;
        for(map<int,int>::iterator iter = freq.begin();
                iter != freq.end();iter ++){
                    if(pq.size() == k){
                        if(iter->second > pq.top().first){
                            pq.pop();
                            pq.push(make_pair(iter->second,iter->first));
                        }
                    }else{
                        pq.push(make_pair(iter->second,iter->first));
                    }
                }
        vector<int> res;
        while(!pq.empty()){
            res.push_back(pq.top().second);
            pq.pop();
        }
        return res;
        
    }
};

2、合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        //vector中存放的是每个链表的头结点
        if(lists.size() == 0)
            return NULL;
        if(lists.size() == 1)
            return lists[0];
        ListNode *p = lists[0];
        for(int i =1;i<lists.size();i++)
            p = merge2Lists(p,lists[i]);
        return p;
    }
    ListNode* merge2Lists(ListNode* l1,ListNode* l2){
        ListNode *head = new ListNode(0);
        ListNode *p = head;
        while(l1&&l2){
            if(l1->val < l2->val){
                p -> next = l1;
                l1 = l1->next;
            }
            else{
                p -> next = l2;
                l2 = l2 -> next;
            }
            p = p->next;
        }
        while(l1){
            p->next = l1;
            l1 = l1->next;
            p = p->next;
        }
        while(l2){
            p->next = l2;
            l2 = l2->next;
            p = p->next;
        }
        return head->next;
    }
};