代码随想录算法训练营day48|198.打家劫舍213.打家劫舍II337.打家劫舍III剑指Offer46.把数字翻译成字符串48.最长不含重复字符的子字符串

文章介绍了使用动态规划解决一系列打家劫舍问题,包括线性序列、环形序列和树形结构的场景。每个问题的核心在于找到最优策略,如选择偷或不偷某个元素,以及如何在不同状态间转移。解决方案涉及数组初始化、递归调用和哈希表去重等编程技巧。
摘要由CSDN通过智能技术生成

198.打家劫舍

题目链接

dp[i]表示,考虑到下标i处所偷的最大金额,仅仅是考虑到,并不一定取该元素。

注意只有一个元素的时候要特殊处理,先判断一下,不然会溢出。有两个元素的情况就不用处理了,因为后面初始化的时候已经取了max。

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-2]+nums[i],dp[i-1]);
        }
        return dp[nums.size()-1];
    }
};

213.打家劫舍II

题目链接

思路:把环形转换成线性,考虑两种情况,一是不考虑第一个元素,二是不考虑最后一个元素。

class Solution {
public:
    int robrange(vector<int>& nums,int start,int end){
        if(start==end) return nums[start];
        vector<int> dp(nums.size()-1,0);//第一处错,不应该是end-1
        dp[0]=nums[start];
        dp[1]=max(nums[start],nums[start+1]);
        for(int i=2;i<nums.size()-1;i++){//不应该是<end
            dp[i]=max(dp[i-2]+nums[start+i],dp[i-1]);//开始写的start+2,应该是start+i
        }
        return dp[nums.size()-2];
    }
    int rob(vector<int>& nums) {
        if(nums.size()==1) return nums[0];
        return max(robrange(nums,0,nums.size()-2),robrange(nums,1,nums.size()-1));
    }
};

这道题还是有待继续研究,改了好几次才通过,因为我的写法是dp数组的下标和nums数组的下标是不同步的,处理的细节要多一点,同步的写法可以参考卡哥的代码。

337.打家劫舍III

题目链接

树形dp。用一个长度为2的一维数组即可,递归的时候系统栈里会帮我们保存每一层的参数。

class Solution {
public:
    vector<int> robtree(TreeNode* cur){
        if(cur==NULL) return vector<int>{0,0};
        vector<int> leftdp=robtree(cur->left);
        vector<int> rightdp=robtree(cur->right);
        int val0=max(leftdp[0],leftdp[1])+max(rightdp[0],rightdp[1]);//左右子节点偷不偷取决于哪个是最大值
        int val1=cur->val+leftdp[0]+rightdp[0];
        return {val0,val1};//上面写了int了,所以就不用写vector<int>了
    }
    int rob(TreeNode* root) {
        vector<int> result=robtree(root);
        return max(result[0],result[1]);
    }
};

剑指 Offer 46. 把数字翻译成字符串

题目链接

思路:本题主要是递推公式。dp[i]表示到下标为i处一共有多少种翻译方法。最后两位一共有两种状态,介于0-25之间和不介于0-25之间,根据这两种情况,如果介于的话,dp[i]=dp[i-1]+dp[i-2](类似于爬楼梯),不介于的话只能当个字符进行翻译,dp[i]=dp[i-1]。

class Solution {
public:
    int translateNum(int num) {
        string str=to_string(num);
        if(str.size()==1) return 1;
        vector<long long> dp(str.size());
        dp[0]=1;
        if((str[0]=='1')||(str[0]=='2'&&str[1]<='5')) dp[1]=2;
        else{
            dp[1]=1;
        }
        for(int i=2;i<str.size();i++){
            if((str[i-1]=='1')||(str[i-1]=='2'&&str[i]<='5')) dp[i]=dp[i-1]+dp[i-2];
            else{
                dp[i]=dp[i-1];
            }
        }
        return dp[str.size()-1];
    }
};

注意函数to_string的使用。

注意开始要进行判断,如果就一位的话,后面写str[1]会溢出。

注意判断条件,如果前一位是1的话,后一位是什么都无所谓,如果是2的话,后一位(当前位)只能<='5'。

48.最长不含重复字符的子字符串

题目链接

思路:双指针+哈希表。这个解法还是很巧妙的。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> hash;
        int res=0;
        for(int i=0,j=0;j<s.size();j++){
            hash[s[j]]++;
            while(hash[s[j]]>1){//这个while循环相当于去重
                hash[s[i]]--;
                i++;//这个不能放前面,因为放前面的话,i开始指向的位置还没减呢
            }
            res=max(res,j-i+1);
        }
        return res;
    }
};

好像还有滑动窗口的解法,还有待研究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值