• [leetcode] 剑指 Offer 专题(七)


    《剑指 Offer》专题第七部。

    66 构建乘积数组

    题目:剑指 Offer 66. 构建乘积数组

    定义:

    [egin{aligned} V_1[i] = prod_{k=0}^{i-1} a[k] = a[0] imes a[1] imes dots imes a[i-1], quad&V_1[0] = 1 \ V_2[i] = prod_{k=i+1}^{n-1} a[k] = a[i+1] imes dots imes a[n-1], quad&V_2[n-1] = 1 end{aligned} ]

    那么有:

    [B[i] = V_1[i] imes V_2[i], 0 le i le n-1 ]

    代码实现:

    class Solution {
    public:
        vector<int> constructArr(vector<int>& a) 
        {
            int n = a.size();
            vector<int> v1(n, 1);
            int p = 1;
            for (int i=0; i<n; i++) v1[i] = p, p *= a[i];
            p = 1;
            vector<int> v2(n, 1);
            for (int i=n-1; i>=0; i--) v2[i] = p, p *= a[i];
            for (int i=0;i<n;i++) v1[i] *= v2[i];
            return v1;
        }
    };
    

    优化空间 v2

    class Solution {
    public:
        vector<int> constructArr(vector<int>& a) 
        {
            int n = a.size();
            vector<int> v1(n, 1);
            int p = 1;
            for (int i=0; i<n; i++) v1[i] = p, p *= a[i];
            p = 1;
            for (int i=n-1; i>=0; i--) v1[i] *= p, p *= a[i];
            return v1;
        }
    };
    

    67 字符串转整数

    题目:剑指 Offer 67. 把字符串转换成整数

    思路很清晰,请看注释。

    class Solution {
    public:
        const uint32_t INTMIN = (1<<31);
        const uint32_t INTMAX = ~INTMIN;
        int strToInt(string str) 
        {
            auto isDigit = [](char c) { return '0' <= c && c <= '9';};
            auto isSign = [](char c) { return c == '+' || c == '-';};
            int len = str.length(), i = 0;
            // 忽律空格
            while (i < len && str[i] == ' ') i++;
            // 第一个非空字符,如果不是 {+, -, 0-9} 那么返回 0 
            if (i == len || (!isSign(str[i]) && !isDigit(str[i]))) return 0;
            // 第一个非空字符是否代表负数
            bool neg = false;
            if (isSign(str[i])) neg = (str[i] == '-'), i++;
            // 求出数字部分的绝对值
            uint64_t val = 0;
            while (i < len && isDigit(str[i]))
            {
                val = val*10 + (str[i]-'0'), i++;
                // 如果超过 [-intmax, +intmax]
                if (val > INTMAX) return neg ? INTMIN: INTMAX;
            }
            return neg ? -val: val;     
        }
    };
    

    68-I 二叉搜索树的最近公共祖先

    题目:剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

    pq 要么都在左子树,要么都在右子树。如果不是,说明当前的子树的 root 就是最近公共祖先。

    class Solution {
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
        {
            auto r = root;
            while (r)
            {
                if (p->val < r->val && q->val < r->val) r = r->left;
                else if (p->val > r->val && q->val > r->val) r = r->right;
                else break;
            }
            return r;
        }
    };
    

    68-II 二叉树的最近公共祖先

    题目:剑指 Offer 68 - II. 二叉树的最近公共祖先

    递归。基于后序遍历,lca(r, p, q) 表示是否在子树 r 中找到 p, q 中的任意一个节点。

    以下图为例:

    当输入 p=7, q=4 时,后序遍历到 7 或 4 时,返回 left = 7, right = 4 给 2 ,这时候 2 就会把自己返回给 5 .

    在遍历 5 的递归层中,left = nullptr, right = 2 ,把 right = 2 返回给 3 。

    同理,在遍历 3 的第一层递归中,left = 2, right = nullptr ,那么就会把 left = 2 返回给 lowestCommonAncestor .

    class Solution {
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            return lca(root, p, q);
        }
        TreeNode *lca(TreeNode *r, TreeNode *p, TreeNode *q)
        {
            if (r == NULL || r == p || r == q) return r;
            auto left = lca(r->left, p, q), right = lca(r->right, p, q);
            if (left && right) return r;
            return left ? left : right;
        }
    };
    

    n 个骰子的点数

    题目:面试题60. n个骰子的点数

    动态规划。

    (P(k)) 是骰子点数和为 (k) 的概率,那么 (P(k)) 等于 (k) 出现的次数除以总事件数目。

    状态定义:(dp[i][j]) 表示有 (i) 个骰子时,点数和为 (j) 的事件数。显然有,(i le j le 6i) .

    转移方程:

    [dp[i][j] = sum_{k=1}^{6} dp[i-1][j-k], quad if quad (i-1) le (j-k) le 6(i-1) ]

    解析:(dp[i][j]) 表示需要用 (i) 个骰子,掷出点数 (j) 。 考虑第 (i) 个骰子的点数可以是 ([1, 6]) 的任意一种,因此 (dp[i][j] = dp[i-1][j-1] + dots + dp[i-1][j-6]) .

    边界条件:(dp[1][1, dots, 6] = 1) .

    虽然二维数组 dpn x 6n 的,但是实际上并不是每个元素都有效,这是由状态方程的定义决定的。前 3 行有效的元素的下标如下:

    i=1 [1, 2, 3, 4, 5, 6]
    i=2 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    i=3 [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
    

    求出 dp[n][n, ..., 6*n] 后,事件总数就是 sum(dp[n][n, ..., 6*n]) .

    class Solution {
    public:
        vector<double> dicesProbability(int n) 
        {
            if (n == 0) return {};
            int rows = n, cols = 6*n;
            vector<vector<int>> dp(rows+1, vector<int>(cols+1, 0));
            for (int j=1;j<=6;j++) dp[1][j] = 1;
            for (int i=2;i<=rows;i++)
            {
                for (int j=i;j<=6*i;j++)
                {
                    for (int k=1; k<=6; k++)
                        if(j-k >= i-1)
                            dp[i][j] += dp[i-1][j-k];
                }
            }
            vector<double> res;
            int total = 0;
            for (int i=n; i<=cols; i++) total+=dp[n][i];
            for (int i=n; i<=cols; i++)
            {
                double x = dp[n][i];
                res.push_back(x/total);
            }
            return res;
        }
    };
    

    空间优化:

    class Solution {
    public:
        vector<double> dicesProbability(int n) 
        {
            int rows=n, cols=6*n;
            vector<int> dp(cols+1, 0);
            for (int i=1; i<=6; i++) dp[i] = 1;
            for (int i=2; i<=rows; i++)
            {
                for (int j=cols; j>=i; j--)
                {
                    int t = 0;
                    for (int k=1; k<=6; k++)
                        if (j-k >= i-1) t += dp[j-k];
                    dp[j] = t;
                }
            }
            vector<double> res;
            int total = 0;
            for (int i=n; i<=cols; i++) total+=dp[i];
            for (int i=n; i<=cols; i++) res.push_back(((double)dp[i]) / total);
            return res;
        }
    };
    
  • 相关阅读:
    C# 中的var关键字
    sql中去掉换行符和回车符
    Linq之旅:Linq入门详解(Linq to Objects)
    c# for 和 foreach
    c# Dictionary
    ASP.NET Web.config学习
    c# 装箱与拆箱的概念
    c# List集合学习
    Index was out of range
    C# double保留四位小数
  • 原文地址:https://www.cnblogs.com/sinkinben/p/13936418.html
Copyright © 2020-2023  润新知