算法D47 | 动态规划9 | 198.打家劫舍 213.打家劫舍II 337.打家劫舍III

本文详细介绍了在LeetCode中使用Python和C++解决打家劫舍系列(198、213、337)的问题,通过动态规划和暴力/递归方法实现,展示了如何在不同情况(单房间、房间连成环、房间连成树)下计算最大收益。
今天就是打家劫舍的一天,这个系列不算难,大家可以一口气拿下。

198.打家劫舍  

视频讲解:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍_哔哩哔哩_bilibili

代码随想录

Python:

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n<=2: return max(nums)
        dp = [0]*n
        dp[0] = nums[0]
        dp[1] = max(nums[:2])
        for i in range(2, n):
            dp[i] = max(dp[i-1], dp[i-2]+nums[i])
        return dp[n-1]

C++:

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size()==1) return nums[0];
        vector<int> dp(nums.size(), 0);
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for (int i=2; i<nums.size(); i++) {
            dp[i] = max(dp[i-1], dp[i-2]+nums[i]);
        }
        return dp[nums.size()-1];
    }
};

213.打家劫舍II  

视频讲解:动态规划,房间连成环了那还偷不偷呢?| LeetCode:213.打家劫舍II_哔哩哔哩_bilibili

代码随想录

Python:

分别考虑[0, n-2] 和 [1, n-1]范围的打家劫舍198,选择两者最大值。

class Solution:
    def robRange(self, nums, start, end):
        if start==end: return nums[start]
        dp = [0] * (end-start+1)
        dp[0] = nums[start]
        dp[1] = max(nums[start], nums[start+1])
        for i in range(start+2, end+1):
            dp[i-start] = max(dp[i-start-1], dp[i-start-2]+nums[i])
        return dp[-1]

    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n==1: return nums[0]
        result1 = self.robRange(nums, 0, n-2)
        result2 = self.robRange(nums, 1, n-1)
        return max(result1, result2)

C++:

class Solution {
public:
    int robRange(vector<int>& nums, int start, int end) {
        if (start==end) return nums[start];
        vector<int> dp(nums.size(), 0);
        dp[start] = nums[start];
        dp[start+1] = max(nums[start], nums[start+1]);
        for (int i=start+2; i<=end; i++) {
            dp[i] = max(dp[i-1], dp[i-2]+nums[i]);
        }
        return dp[end];
    }
    int rob(vector<int>& nums) {
        if (nums.size()==1) return nums[0];
        int result1 = robRange(nums, 0, nums.size()-2);
        int result2 = robRange(nums, 1, nums.size()-1);
        return max(result1, result2);
    }
};

337.打家劫舍III  

视频讲解:动态规划,房间连成树了,偷不偷呢?| LeetCode:337.打家劫舍3_哔哩哔哩_bilibili

代码随想录

Python暴力:

class Solution:
    def __init__(self):
        self.umap = {}

    def rob(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        if not root.left and not root.right: return root.val
        if root in self.umap.keys(): return self.umap[root]
        # 偷root
        val1 = root.val
        if root.left: val1 += self.rob(root.left.left) + self.rob(root.left.right)
        if root.right: val1 += self.rob(root.right.left) + self.rob(root.right.right)
        # 不偷root
        val2 = self.rob(root.left) + self.rob(root.right)
        self.umap[root] = max(val1, val2) 
        return max(val1, val2)

C++:暴力

class Solution {
public:
    unordered_map<TreeNode*, int> umap;
    int rob(TreeNode* root) {
        if (root==NULL) return 0;
        if (root->left==NULL && root->right==NULL) return root->val;
        if (umap[root]) return umap[root];
        // 偷root
        int val1 = root->val;
        if (root->left) val1 += rob(root->left->left) + rob(root->left->right);
        if (root->right) val1 += rob(root->right->left) + rob(root->right->right);
        // 不偷root
        int val2 = rob(root->left) + rob(root->right);
        umap[root] = max(val1, val2);
        return max(val1, val2);
    }
};

Python动态规划:

class Solution:
    def traversal(self, node):
        if not node: return (0, 0)
        left = self.traversal(node.left)
        right = self.traversal(node.right)
        # 不偷node
        val1 = max(left[0], left[1]) + max(right[0], right[1])
        # 偷node
        val2 = node.val + left[0] + right[0]
        return (val1, val2)

    def rob(self, root: Optional[TreeNode]) -> int:
        dp = self.traversal(root)
        return max(dp)
        

C++动态规划:

class Solution {
public:
    vector<int> traversal(TreeNode* node) {
        if (node==NULL) return vector<int>{0, 0};
        vector<int> left = traversal(node->left);
        vector<int> right = traversal(node->right);
        //不偷node
        int val1 = max(left[0], left[1]) + max(right[0], right[1]);
        //偷node
        int val2 = node->val + left[0] + right[0];
        return {val1, val2};
    }
    int rob(TreeNode* root) {
        vector<int> dp = traversal(root);
        return max(dp[0], dp[1]);
    }
};

<think> 我们面对的核心问题是在宿主机驱动版本为535.154.05(对应CUDA 12.2)的情况下,尝试运行一个内部使用CUDA 12.4.1的容器时,出现了`RuntimeError: Unexpected error from cudaGetDeviceCount(). Error 804: forward compatibility was attempted on non supported HW`错误。这个错误表明容器试图使用向前兼容特性,但宿主机硬件不支持。 ### 错误原因分析 1. **CUDA向前兼容性要求**:CUDA 12.4.1运行时要求宿主机驱动版本至少为535.86.10(参考[NVIDIA CUDA兼容性文档](https://docs.nvidia.com/deploy/cuda-compatibility/index.html)),而宿主机当前驱动版本535.154.05虽然高于最低要求,但实际使用中仍出现兼容性错误。 2. **硬件限制**:错误代码804明确表示硬件不支持向前兼容。常见于以下情况: - 旧架构GPU(如Maxwell/Pascal,包括GTX 1080、Tesla P100等)[^1] - 某些虚拟机或云实例的虚拟化GPU ### 解决方案 #### 方案1:升级宿主机NVIDIA驱动(推荐) 将宿主机驱动升级至支持CUDA 12.4.1的版本(≥535.86.10): ```bash # 宿主机操作 sudo apt-get purge nvidia-* sudo add-apt-repository ppa:graphics-drivers/ppa sudo apt-get update sudo apt-get install nvidia-driver-550 # 安装550+版本驱动 sudo reboot ``` 验证驱动版本: ```bash nvidia-smi | grep "Driver Version" # 应输出≥550.54.14的版本号 ``` #### 方案2:容器内降级CUDA至12.2 若无法升级宿主机驱动,需调整容器内环境: ```bash # 进入容器操作 docker exec -it your_container_name bash # 降级PyTorch到兼容CUDA 12.2的版本 pip install torch==2.2.0 torchvision==0.17.0 --index-url https://download.pytorch.org/whl/cu121 # 确保其他CUDA相关库也降级 conda install cudatoolkit=12.2 -c nvidia # 如果使用conda ``` #### 方案3:强制禁用向前兼容(临时方案) 在容器启动时添加环境变量: ```bash docker run -it --gpus all \ -e "CUDA_VISIBLE_DEVICES=0" \ # 指定使用第一个GPU -e "CUDA_FORCE_FORWARD_COMPAT=0" \ # 禁用向前兼容 your_image_name ``` ### 验证步骤 1. **宿主机驱动验证**: ```bash nvidia-smi -q | grep "Driver Version" ``` 确认版本≥535.86.10 2. **容器内功能测试**: ```bash docker exec -it your_container python -c "import torch; print(torch.cuda.is_available())" ``` 应输出`True` ### 硬件兼容性检查 ```bash # 查看GPU架构 nvidia-smi -q | grep "Product Architecture" ``` - 若输出`Pascal`/`Maxwell`等旧架构名称,则**必须采用方案2或方案3** - 若输出`Turing`/`Ampere`/`Ada Lovelace`等新架构,方案1可解决问题 > **关键提示**:Tesla P100(Pascal架构)物理上不支持向前兼容,必须降级容器内CUDA版本[^1]。RTX 30/40系显卡升级驱动即可。 --- ### §§相关问题§§ 1. 如何查询NVIDIA GPU的架构类型? 2. 如何在不升级驱动的情况下运行高版本CUDA应用? 3. Docker容器中如何正确配置NVIDIA环境变量? </think> 根据你的宿主机驱动版本(535.154.05,CUDA 12.2)和容器内CUDA版本(12.4.1)的差异,以下是解决`RuntimeError: Unexpected error from cudaGetDeviceCount()`错误的完整方案: ### 核心问题分析 错误代码`Error 804: forward compatibility was attempted on non supported HW`表明: 1. **驱动版本不匹配**:CUDA 12.4.1要求宿主机驱动≥535.86.10([NVIDIA官方兼容性表](https://docs.nvidia.com/deploy/cuda-compatibility/index.html)) 2. **硬件限制**:旧架构GPU(如Pascal/Maxwell)不支持向前兼容特性[^1] 3. **容器配置冲突**:容器内高版本CUDA试图调用宿主机不支持的API ### 解决方案(按优先级推荐) #### ✅ 方案1:升级宿主机驱动(首选) ```bash # 1. 清理旧驱动 sudo apt purge nvidia-* -y sudo rm /etc/apt/sources.list.d/*nvidia* # 2. 添加官方驱动仓库 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list # 3. 安装550+版本驱动(支持CUDA 12.4+) sudo apt update sudo apt install nvidia-driver-550 -y # 4. 重启并验证 sudo reboot nvidia-smi # 应显示Driver Version: 550+ ``` #### ⚠️ 方案2:容器内降级CUDA(无需升级驱动) ```bash # 进入容器 docker exec -it 980ec0d47d82 bash # 降级PyTorch和CUDA工具包 pip install --upgrade torch==2.2.0 torchvision==0.17.0 torchaudio==2.2.0 --index-url https://download.pytorch.org/whl/cu121 # 确认版本 python -c "import torch; print(f&#39;PyTorch {torch.__version__}, CUDA {torch.version.cuda}&#39;)" # 应输出:PyTorch 2.2.0, CUDA 12.1 ``` #### 🛠️ 方案3:强制兼容模式(临时方案) ```bash # 启动容器时添加环境变量 docker run -it --gpus all \ -e CUDA_VISIBLE_DEVICES=0 \ # 指定单个GPU -e CUDA_FORCE_FORWARD_COMPAT=0 \ # 禁用向前兼容 -e LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libcuda.so.535 \ # 绑定特定驱动版本 your_image_name ``` ### 验证步骤 在容器内执行诊断: ```bash docker exec 980ec0d47d82 python -c \ "import torch; print(f&#39;Devices: {torch.cuda.device_count()}&#39;); torch.zeros(1).cuda()" ``` 成功输出应包含: ``` Devices: 1 ``` ### 关键配置说明 1. **驱动版本对照表**: | CUDA版本 | 最低驱动要求 | |---------|-------------| | 12.2 | 535.86.10 | | 12.4 | 550.54.15 | *宿主机驱动535.154.05仅正式支持到CUDA 12.2* 2. **硬件兼容性检查**: ```bash nvidia-smi -q | grep -E "Product Name|Architecture|CUDA Version" ``` 若架构显示`Pascal`或`Maxwell`,必须使用方案2降级 > **重要提示**:对于生产环境,推荐采用方案1升级驱动。Tesla P100/Pascal等旧架构硬件需永久使用方案2[^1] --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值