算法分析与设计课程作业第十五周#1#2#3

算法分析与设计课程作业第十五周#1#2#3

这次选了两道与期中考题目相似的题目以及一道动态规划题来做。

98. Validate Binary Search Tree

Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

Example 1:
2
/ \
1 3
Binary tree [2,1,3], return true.

Example 2:
1
/ \
2 3
Binary tree [1,2,3], return false.

相似的期中考题目

输入两个二叉树T1和T2,要求对T1和T2进行合并. 合并是指将二叉树同一位置节点上的数求和,作为合并后二叉树相应位置节点的数值. 如果某个位置上只有一个二叉树有节点,则合并后的二叉树对应位置上的节点上的数值就等于这个节点上的数值.
例如:
这里写图片描述
T1和T2的结点数均不多于100000,每个结点的数值在1和1000之间.

请为下面的Solution类实现解决上述问题的merge函数,函数的两个参数T1和T2分别代表两个二叉树的根节点,函数返回值为合并后的二叉树的根节点.

思路

这道题有一个简单的思路就是中序遍历该树,看能否得到一个有序的序列。
不过,期中考有道类似题(如上,都是对树的操作)用了分而治之的方法,所以也想试试这道题能不能用类似的思路。
期中考题代码:

class Solution {
public:
    TreeNode* merge(TreeNode* T1, TreeNode* T2) {
        if(T1 != NULL && T2 != NULL){
            TreeNode * root = new TreeNode(T1->val + T2->val);
            root->left = merge(T1->left, T2->left);
            root->right = merge(T1->right, T2->right);
            return root;
        }
        else if(T1 == NULL){
            return T2;
        }
        else{
            return T1;
        }
    }
};

由此,可类似地想到,判断一棵树是否为二叉搜索树,可分别判断以其根节点的两个子节点为根节点的子树是否为二叉搜索树以及是否左子节点值小于根节点值小于右子节点值。
不过,还有个问题就是,就算两棵子树为二叉搜索树,该树仍未足够成为一棵二叉搜索树,还有一个要求就是左子树的右子节点(左子树拥有最大值的节点)的值比树的根节点值小,右子树的左子节点(右子树拥有最小值的节点)的值比树的根节点值大。由此,代码如下:

代码

/**
 * 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:
    bool isValidBST(TreeNode* root,long long min = (long long)INT_MIN -1, long long max = (long long)INT_MAX + 1) {
        if(root == NULL) return true;
        if(root->left != NULL&& (root->left->val >= root->val || root->left->val <= min)){
            return false;
        }
        if(root->right != NULL&& (root->right->val <= root->val || root->right->val >= max)){
            return false;
        }
        return isValidBST(root->left, min, root->val)&&isValidBST(root->right, root->val, max);
    }
};

337. House Robber III

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the “root.” Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that “all houses in this place forms a binary tree”. It will automatically contact the police if two directly-linked houses were broken into on the same night.
Determine the maximum amount of money the thief can rob tonight without alerting the police.
Example 1:
3
/ \
2 3
\ \
3 1
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

Example 2:
3
/ \
4 5
/ \ \
1 3 1
Maximum amount of money the thief can rob = 4 + 5 = 9.

相似的期中考题目

从数列A[0], A[1], A[2], …, A[N-1]中选若干个数,要求对于每个i(0<=i < N-1),A[i]和A[i+1]至少选一个数,求能选出的最小和.
1 <= N <= 100000, 1 <= A[i] <= 1000
请为下面的Solution类实现解决上述问题的函数minSum,函数参数A是给出的数列,返回值为所求的最小和.
class Solution {
public:
int minSum(vector& A) {

}

};
例1:A = {2, 5, 2},答案为4.
例2:A = {2, 5, 4},答案为5.
注意:你只需要提交Solution类的代码,你在本地可以编写main函数测试程序,但不需要提交main函数的代码. 注意不要修改类和函数的名称.

思路

相邻的至多选一个(337)与至少选一个(期中考)其实是类似的,不过337题将序列扩展为树,就稍微复杂了点。
可以这样考虑:对于一棵子树,对于其根节点,要么选,则根节点的直接子节点就不能选,所求为根节点值加上两个左右子节点分别的左右子节点(称为孙节点吧)形成的子树所能抢劫的之和;要么不选,则所求相当于求两个左右子节点形成的子树所能抢劫的之和(注意此时未必就代表要选根节点的两个左右子节点)。
其实这也是一个动态规划问题,相当于课本所讲的记忆化搜索(因为比较难用一个dp数组记录得到的信息,只能交给递归)。
从这道题与期中考题目也可以得出其中一个解决动态规划问题的思路,就是对某一个元素,考虑选与不选的情况,再进行比较,不过还是要具体问题具体分析。

代码

/**
 * 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:
    int dfs(TreeNode* root, int &l, int &r){
        if(root == NULL){
            l = 0;
            r = 0;
            return 0;
        }
        int ll, lr, rl, rr;
        l = dfs(root->left, ll, lr);
        r = dfs(root->right, rl, rr);
        return max(root->val + ll + lr + rl + rr, l + r);
    }
    int rob(TreeNode* root) {
        int l, r;
        return dfs(root, l, r);
    }
};

221. Maximal Square

Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area.
For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.

思路

这可以说是一道相当简洁的题目了。现在的问题是:用动态规划的思想来做,dp数组用来表示什么。
曾经想过dp[i][j]表示matrix[i][j]所在最大正方形的边长,但这样问题是难以计算状态转移,因为这样无法得知(储存)其所在的最大正方形是哪个,就算能得知,也未必能根据dp[i][j]进行状态转移。
既然这样,就用dp[i][j]表示以matrix[i][j]为右下角的最大正方形的边长, 这样,所求即max{dp[i][j]},也比较容易计算状态转移(具体见下)。

代码

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        int m = matrix.size();
        if(m == 0) return 0;
        int n = matrix[0].size();
        if(n == 0) return 0;
        vector<vector<int>> dp(m, vector<int>(n, 0));//dp[i][j]表示以matrix[i][j]为右下角的正方形的面积
        int maximaledge = 0;
        for(int i = 0; i < m; i++){
            if(matrix[i][0] == '1'){
                dp[i][0] = 1;
                maximaledge = 1;
            }
        }
        for(int j = 0; j < n; j++){
            if(matrix[0][j] == '1'){
                dp[0][j] = 1;
                maximaledge = 1;
            }
        }
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++){
                if(matrix[i][j] == '1'){
                    dp[i][j] = min(min(dp[i-1][j-1], dp[i-1][j]), dp[i][j-1]) + 1;
                    maximaledge = max(maximaledge, dp[i][j]);
                }
            }
        }
        return maximaledge * maximaledge;

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值