leetcode:打家劫舍III && leetcode:计算比特位数

打家劫舍III:题目描述

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:

输入: [3,2,3,null,3,null,1]

 3
/ \

2 3
\ \
3 1

输出: 7
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

示例 2:

输入: [3,4,5,1,3,null,1]

 3
/ \

4 5
/ \ \
1 3 1

输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.

解题思路

  1. 递归的方法
    分两种情况:

选择头结点

  • 那么它的子节点就不能选

和不选择头节点

  • 它的子节点都可选

最后取两者的最大值

这种方法实现简单,但是超过了时间复杂度。
因为我们在计算的时候,它的左子树的子节点和右子树的子节点都遍历了两次。

class Solution {
public:
    int rob(TreeNode* root) {
        if(root == nullptr) return 0;
        
        if(root->left == nullptr && root->right == nullptr)
            return root->val;
        
        //是否选择头结点
        int a = root->val;
        
        if(root->left != nullptr)
            a += rob(root->left->left) + rob(root->left->right);
        if(root->right != nullptr)
            a += rob(root->right->left) + rob(root->right->right);
        
        //不选择头结点
        int b = 0;
        b += rob(root->left) + rob(root->right);
        
        return max(a,b); 
    }
};
  1. 在遍历左右节点的时候,记录下选取头结点的值和不选取头结点的值
class Solution {
public:
    int rob(TreeNode* root) {
        if(root == nullptr) return 0;
        vector res = robHelp(root);  
        return max(res[0],res[1]); 
    }
    vector robHelp(TreeNode * root){
        if(root == nullptr)
            return {0,0};
        vector l = robHelp(root->left);
        vector r = robHelp(root->right);
        
        //第一个是不选择头结点的值,第二个是选择头结点的值 + 不选取左节点的值 + 不选取右节点的值
        return {max(l[0],l[1]) + max(r[0],r[1]),root->val + l[0] + r[0]};
    }
};

计算比特位数:题目描述

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

示例 1:

输入: 2
输出: [0,1,1]

示例 2:

输入: 5
输出: [0,1,1,2,1,2]

进阶:

给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
要求算法的空间复杂度为O(n)。
你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。

解题思路

  1. 从0到nums,就算每个数的比特位数
class Solution {
public:
    vector countBits(int num) {
        vector res;
        for(int i = 0; i <= num; i++){
            int k = i;
            int count = 0;
            while(k > 0){
                count++;
                k = (k - 1) & k;
            }
            res.push_back(count);
        }
        
        return res;
    }
};
  1. 分奇数和偶数
    如果是奇数:则它的1的个数等于它前面的偶数的1的个数 + 1
    如果偶数,则它的1的个数就和该数除以的个数相等。

0: 0
2: 10
4: 100
8: 1000
16: 1 0000

1: 1
3: 11
6:110

因为偶数最后面一定有一个0,则右移就是将这个0除掉,那么它的1的个数是不变的。
如果是奇数,那么就是在偶数的0上面加一个1,那么它肯定是它前面偶数的1的个数加1

class Solution {
public:
    vector countBits(int num) {
        
        vector res(num + 1);
        for(int i = 0; i <= num; i++){
            if(i % 2 == 0){
                res[i] = res[i / 2];
            }else{
                res[i] = res[i - 1] + 1;
            }
        }
        return res;
    }
};

你可能感兴趣的:(算法)