LeetCode 热题 HOT 100 打卡计划 | 第二十天 | 每日进步一点点

83 阅读3分钟

图片.png

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

198. 打家劫舍

思路

(动态规划) O(n)

给定一个代表金额的非负整数数组nums,相邻房间不可偷,让我们输出可以偷窃到的最高金额。

样例:

图片.png

如样例所示,nums = [2,7,9,3,1],偷窃135号房间可以获得最高金额12,下面来讲解动态规划的做法。

状态表示: f[i]表示偷窃1号到i号房间所能获得的最高金额。那么,f[n]就表示偷窃1号到n号房间所能获得的最高金额,即为答案。

状态计算:

假设有i间房间,考虑最后一间偷还是不偷房间,有两种选择方案:

  • 1、偷窃前i-1间房间,不偷窃最后一间房间,那么问题就转化为了偷窃1号到i - 1号房间所能获得的最高金额,即f[i] = f[i-1]

图片.png

  • 2、偷窃前i - 2间房间和最后一间房间 (相邻的房屋不可闯入),那么问题就转化为了偷窃1号到i- 2号房间所能获得的最高金额再加上偷窃第i号房间的金额,即f[i] = f[i - 2] + nums[i]。 (下标均从1开始)

图片.png

两种方案,选择其中金额最大的一个。因此状态转移方程为: f[i] = max(f[i - 1], f[i - 2] + nums[i])。 (下标均从1开始)

初始化: f[1] = nums[0],偷窃1号房间所能获得的最高金额为nums[0]

实现细节:

我们定义的状态表示f[]数组和nums[]数组下标均是从1开始的,而题目给出的nums[]数组下标是从0开始的。为了一 一对应,状态转移方程中的nums[i]的值要往前错一位,取nums[i - 1],这点细节希望大家可以注意一下。

时间复杂度分析: O(n),其中 n是数组长度。只需要对数组遍历一次。

c++代码


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

338. 比特位计数

思路

(动态规划) O(n)

状态表示: f[i]表示i 的二进制表示中1的个数。

状态计算:

考虑i的奇偶性,有两种不同选择:

  • i是偶数,则f[i] = f[i/2],因为 i/2 * 2 本质上是i/2的二进制左移一位,低位补零,所以1的数量不变。
  • i是奇数,则f[i] = f[i - 1] + 1,因为如果i为奇数,那么 i - 1必定为偶数,而偶数的二进制最低位一定是0,那么该偶数 +1 后最低位变为1且不会进位,所以奇数比它上一个偶数二进制表示上多一个1

初始化: f[0] = 0

时间复杂度分析: O(n)。

c++代码


 class Solution {
 public:
     vector<int> countBits(int n) {
         vector<int> f(n + 1);
         f[0] = 0; //初始化
         for(int i = 1; i <= n; i++){
             if(i & 1) f[i] = f[i - 1] + 1;
             else f[i] = f[i >> 1];
         }
         return f;
     }
 };

200. 岛屿数量

思路

(深度优先遍历)

  1. 从任意一个陆地点开始,即可通过四连通的方式,深度优先搜索遍历到所有与之相连的陆地,即遍历完整个岛屿。每次将遍历过的点清 0
  2. 重复以上过程,可行起点的数量就是答案。

时间复杂度分析: 由于每个点最多被遍历一次,故时间复杂度为 O(n*m)

空间复杂度分析: 最坏情况下,需要额外O(n*m) 的空间作为系统栈。

c++代码

 class Solution {
 public:
     vector<vector<char>> g;
     int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
     int numIslands(vector<vector<char>>& grid) {
         g = grid;
         int cnt = 0;
         for(int i = 0; i < g.size(); i++)
             for(int j = 0; j < g[i].size(); j++){
                 if(g[i][j] == '1'){
                     dfs(i, j);
                     cnt++;
                 }
             }
         return cnt;    
     }
 ​
     void dfs(int x, int y){
         g[x][y] = '0';
         for(int i = 0; i < 4; i++){
             int a = x + dx[i], b = y + dy[i];
             if(a < 0 || a >= g.size() || b < 0 || b >= g[a].size() || g[a][b] == '0') continue;
             dfs(a, b);
         }
     }
 };