代码题(42)— 打家劫舍

1、198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

  这道题的本质相当于在一列数组中取出一个或多个不相邻数,使其和最大。那么我们对于这类求极值的问题首先考虑动态规划Dynamic Programming来解,我们维护一个一位数组dp,其中dp[i]表示到i位置时不相邻数能形成的最大和,那么递推公式怎么写呢,我们先拿一个简单的例子来分析一下,比如说nums为{3, 2, 1, 5},那么我们来看我们的dp数组应该是什么样的,首先dp[0]=3没啥疑问,再看dp[1]是多少呢,由于3比2大,所以我们抢第一个房子的3,当前房子的2不抢,所以dp[1]=3,那么再来看dp[2],由于不能抢相邻的,所以我们可以用再前面的一个的dp值加上当前的房间值,和当前房间的前面一个dp值比较,取较大值当做当前dp值,所以我们可以得到递推公式dp[i] = max(num[i] + dp[i - 2], dp[i - 1]), 由此看出我们需要初始化dp[0]和dp[1],其中dp[0]即为num[0],dp[1]此时应该为max(num[0], num[1]),

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.empty())
            return 0;
        vector<int> dp(nums.size());
        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]);//动态规划,到第i家为止最大和
        }
        //return dp[nums.size()-1];
        return dp.back();

    }
};

2、213. 打家劫舍 II

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

  现在房子排成了一个圆圈,则如果抢了第一家,就不能抢最后一家,因为首尾相连了,所以第一家和最后一家只能抢其中的一家,或者都不抢,那我们这里变通一下,如果我们把第一家和最后一家分别去掉,各算一遍能抢的最大值,然后比较两个值取其中较大的一个即为所求。那我们只需参考之前的House Robber 打家劫舍中的解题方法,然后调用两边取较大值。

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        if(n<=0)
            return 0;
        if(n == 1)
            return nums[0];
        return max(rob(nums,0,n-1), rob(nums,1,n));// 去掉第一个或者最后一个,分别求值找最大值

    }
    int rob(vector<int> &nums, int left, int right)
    {
        if(right-left<=1)
            return nums[left];
        vector<int> dp(right);
        dp[left] = nums[left];
        dp[left+1] = max(nums[left], nums[left+1]);
        for(int i = left+2;i<right;++i)
        {
            dp[i] =max(dp[i-1], dp[i-2]+nums[i]);
        }
        return dp.back();
    }
};

原文地址:https://www.cnblogs.com/eilearn/p/9448109.html

时间: 2024-11-06 14:38:57

代码题(42)— 打家劫舍的相关文章

面试题收集-java面试题及答案(基础题122道,代码题19道)

JAVA相关基础知识1.面向对象的特征有哪些方面?1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二是数据抽象.2.继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法.对象的一个新类可以从现有的类中派生,这个过程称为类继承.新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类).派

Java面试题及答案(基础题122道,代码题19道)

转载自:http://www.blogjava.net/fanyingjie/archive/2007/06/27/126467.aspx JAVA相关基础知识1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二是数据抽象.2.继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法.对象的

java常见面试题及答案(基础题122道,代码题19道)

JAVA相关基础知识1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二是数据抽象.2.继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法.对象的一个新类可以从现有的类中派生,这个过程称为类继承.新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类).派

java面试题及答案(基础题122道,代码题19道)(转)

JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二是数据抽象. 2.继承: 继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法.对象的一个新类可以从现有的类中派生,这个过程称为类继承.新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父

【vijos】1765 Caculator(代码题)

https://vijos.org/p/1765 这题用白书的方法是n^2的,所以我tle了一个点..sad. 我稍微优化了一下. 这个题给我最大的感受不是这个题本身,而是我感受到了自己思考以后并认真查错一次提交获得这么高分的感受. 做题一定要认真.仔细. 写这些题最重要的就是仔细,一些细节方面没处理好,那么就会挂了,而陷入调试的泥潭. 想想我以前写的程序,哪个不是这样呢? 首先一定要有个大概的框架了且自己反复论证这样做是正确的(不考虑满分的情况下,可以充当暴力以便对拍和骗分) 一定要反复论证!

刷题42. Trapping Rain Water

一.题目说明 题目是42. Trapping Rain Water,翻译起来就是"接雨水".给n个非负正数代表高度,每个正数宽度为1,让计算能多少雨水.题目难度是Hard 二.我的解法 这个题目是找"坑",然后计算里面可以存的"雨".总共提交了5次,前面几次都是边界错误. 代码如下: #include<iostream> #include<vector> using namespace std; class Solutio

代码题

一.如何去小数点前两位,并四舍五入? double d=1256.22d; d=d/100; System.out.println(Math.round(d)*100); 二.如何格式化日期? Import java.text.SimpleDateFormat; SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date dat=new Date(); String str=sdf.format(dat)

看数据结构写代码(42)最小生成树

首先给出 一些 概念问题: 1.生成树: 一个n个顶点的 连通图 的 极小连通子图. 它含有n个顶点,但只有 n-1条边,不存在回路. 2.最小生成树:一个带权的 无向连通图,求出 各边权值相加  最小的 生成树,叫做最小生成树. 所以 求最小生成树  首先 要满足: 1. 首先 是 无向图 2. 必须是 连通图(任意两个顶点可达)3.带权 简单的说 就是 必须是 连通网. 求 最小生成树,严蔚敏的 数据结构 给出了 两种 方法:普里姆算法和 克鲁斯卡尔算法. 普里姆算法: 克鲁斯卡尔算法: 克

逻辑代码题:如果昨天是明天,那今天就是周五了

题目:I wish yesterday is tomorrow, then today is Friday. What is the actual date today? 思路:1.我希望昨天是明天,也就是说 假设的昨天 是 实际的明天 : yesterday=tomorrow 2.实际的明天 就是 假设的今天-1 : tomorrow=today-1 3. 假设的今天是周五:today=5 1 //wish today is 5,so wish yesterday is 4 .actual t