leetcode刷题笔录-3

13.三角形

  • 给出一个“三角形”,找到从底边到顶点的最小路径(即,路径上所有元素加和最小)。路径只能跨越相邻的点。如给出:
         [2],
        [3,4],
       [6,5,7],
      [4,1,8,3]

    那么就返回11,因为最短路径1-5-3-2的和为11。

  • 思路:很简单,与算法导论中一道“国际象棋”棋盘的题很类似。从底边开始生成到每个点的最小路径加和。
  • 实现:
    class Solution {
    public:
        int minimumTotal(vector<vector<int> > &triangle) {
            int n = triangle.size();
            vector<vector<int>> sum(triangle);
            for(int i=n-2; i>=0; i--){
                for (int j=0; j<=i; j++){
                    sum[i][j] += sum[i+1][j]<sum[i+1][j+1] ? sum[i+1][j] : sum[i+1][j+1];
                }
            }
            return sum[0][0];
        }
    };

14.帕斯卡三角形

  • 给出nRows,生成帕斯卡三角形。如给出nRows=5,则返回:
    [
         [1],
        [1,1],
       [1,2,1],
      [1,3,3,1],
     [1,4,6,4,1]
    ]
  • 思路:简单,过。
  • 实现:
    class Solution {
    public:
        vector<vector<int> > generate(int numRows) {
            vector<vector<int>> triangle;
            for (int i=0; i<=numRows-1; i++){
                vector<int> row;
                if (i==0){
                    row = vector<int>(1,1);
                }
                else{
                    for (int j=0; j<=i; j++){
                        if (j==0)
                        {
                            row.push_back(triangle[i-1][j]);
                        }
                        else if (j==i)
                        {
                            row.push_back(triangle[i-1][j-1]);
                        }
                        else{
                            row.push_back(triangle[i-1][j-1]+triangle[i-1][j]);
                        }
                    }
                }
                triangle.push_back(row);
            }
            return triangle;
        }
    };  

15.帕斯卡三角形2

  • 给出索引值k,返回帕斯卡三角形中的第k行。如给出k=3,则返回[1,3,3,1]。只允许使用O(k)的额外空间。
  • 思路:也很简单,因为计算每一行只需要用到上一行的值,而跟上一行之上没有关系。所以只需要维护三角形中至多两行,空间消耗为O(2k)=O(k)。
  • 实现:
    class Solution {
    public:
        vector<int> getRow(int rowIndex) {
            vector<int> tmp;
            vector<int> current;
            for (int i=0; i<=rowIndex; i++){
                current = vector<int>();
                if (i==0){
                    current.push_back(1);
                }
                else{
                    for(int j=0; j<=i; j++){
                        if (j==0 || j==i){
                            current.push_back(1);
                        }
                        else{
                            current.push_back(tmp[j-1]+tmp[j]);
                        }
                    }
                }
                tmp = current;
            }
            return current;
        }
    };

16.下一个右节点

  • 给出一个最简单的二叉树,树的节点有一个额外的域next(见代码注释),指向相同深度节点中右边一个节点,如果已经是同一深度最右的节点了,那么next域则为NULL。现在的二叉树中所有节点next域都为NULL,处理该二叉树使得其具有上述性质。在这个问题中,假设二叉树是完整的(所有叶子节点在同一深度)。比如给出:
             1
           /  \
          2    3
         / \  / \
        4  5  6  7

    则返回:

             1 -> NULL
           /  \
          2 -> 3 -> NULL
         / \  / \
        4->5->6->7 -> NULL
  • 思路:正常的进行前序遍历,对每一个节点:
    • 使K的左子结点next域指向K的右子结点
    • 使K的右子结点指向K的next节点的左子节点
    • 注意我们使用的是前序遍历,这说明在处理K节点的左子结点和右子结点时,我们已经处理了K节点的父节点的左子结点和右子结点(这就包括K),K节点的next域已经指向了应该指向的位置。
  • 实现:
    /**
     * Definition for binary tree with next pointer.
     * struct TreeLinkNode {
     *  int val;
     *  TreeLinkNode *left, *right, *next;
     *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
     * };
     */        
    class Solution {
    public:
        void connect(TreeLinkNode *root) {
            if (root == NULL){
                return;
            }
            if (root->left != NULL && root->right != NULL){
                root->left->next = root->right;
                root->right->next = root->next==NULL ? NULL : root->next->left;
            }
            connect(root->left);
            connect(root->right);
        }
    };

17.下一个右节点2

  • 同上一题,但此时二叉树不再是完整的了。同时,要求仅使用常量规模的额外存储空间。如,给出:
             1
           /  \
          2    3
         / \    \
        4   5    7

    应当返回:

             1 -> NULL
           /  \
          2 -> 3 -> NULL
         / \    \
        4-> 5 -> 7 -> NULL
  • 思路:由于只能使用常量规模的额外空间了,所以不使用递归而使用循环遍历。节点的next域使我们的按行遍历变得很方便(这种广度优先遍历本来是需要队列支持的)。在实现中,按照行遍历二叉树,当处理某个节点的子节点时,该节点所在的行都已经被next指针连接起来了。根据这篇博文的思路:
    • 方法getNext(node)的作用是:返回节点的左节点,如果没有就返回其右节点,如果还没有就返回其next(同一行右侧节点)节点的左节点,其右节点……依此类推。
    • 这个方法有两个作用:
      • 当前行处理完成之后,根据当前行的首节点(我们使用它来维持外部循环),寻找下一行的首节点:如果首节点有左节点,那下一行的首节点就是左节点,没有,则下一行的首节点就是右节点。如果当前行首节点是叶子节点,那么下一行的首节点就是next节点的左节点,右节点……依此类推。
      • 处理当前节点(我们用它来维持外部循环)的右节点时,或者处理当前节点的左节点且当前节点没有右节点时,那么next指针就需要指向当前节点的next节点的左节点,右节点(如果没有左节点)……依此类推。
  • 实现:
    /**
     * Definition for binary tree with next pointer.
     * struct TreeLinkNode {
     *  int val;
     *  TreeLinkNode *left, *right, *next;
     *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void connect(TreeLinkNode *root) {
            if (root==NULL){
                return;
            }
            TreeLinkNode* lineHead = root;
            TreeLinkNode* node = root;
            while(lineHead){
                node = lineHead;
                while(node){
                    conectChildren(node);
                    node = node->next;
                }
                lineHead = getNext(lineHead);
            }
        }
    private:
        void conectChildren(TreeLinkNode* node){
            // Consider node->left
            if (node->left != NULL){
                if (node->right!=NULL){
                    node->left->next = node->right;
                }
                else{
                    node->left->next = getNext(node->next);
                }
            }
            // Consider node->right
            if (node->right != NULL){
                node->right->next = getNext(node->next);
            }
        }
        TreeLinkNode* getNext(TreeLinkNode* node){
            if (node == NULL){
                return NULL;
            }
            else if (node->left != NULL){
                return node->left;
            }
            else if (node->right != NULL){
                return node->right;
            }
            else{
                return getNext(node->next);
            }
        }
    };
posted @ 2013-04-02 09:08  一叶斋主人  阅读(1275)  评论(0编辑  收藏  举报