文章目录
第一题: 最长连续序列
LeetCode: 剑指 Offer II 119. 最长连续序列
描述:
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
解题思路:
- 首先将数组元素存入到HashSet中
- 找到当前元素, 判断是否有比他小1的元素
- 如果没有. 那么判断是否有比他大1的元素, 循环,记录有多少满足的元素.
- 如果有, 直接进入下一次循环.
- 返回记录中最大的次数
代码实现:
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
// 第一次遍历将数组存入哈希中
for(int val : nums) {
set.add(val);
}
int ans = 0;
for(int val : nums) {
// 判断是否有比当前元素小1的
if(!set.contains(val-1)){
// 这里是没有比当前元素小1的
int ret = val + 1;
int count = 1;
// 这里的count为1, 因为要算上自己
while (set.contains(ret)) {
count++;
ret++;
}
ans = Math.max(ans,count);
}
}
return ans;
}
}
第二题: 最少的硬币数目
LeetCode: 剑指 Offer II 103. 最少的硬币数目
描述:
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
解题思路:
动态规划思路:
- 状态 F(i) : 表示凑出当前i个硬币的最少硬币数目
- 状态转移方程: F[i] = Math.min(F[i],F[i-coins[j]]+1)
- 初始状态: F(0) = 0;
- 返回结果: F(amount)
代码实现:
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
// amount+1可以避免溢出
Arrays.fill(dp,amount+1);
dp[0] = 0;
for(int i = 1; i < amount+1; i++) {
for(int j = 0; j < coins.length; j++) {
// 硬币面额要小于总金额
if(coins[j] <= i) {
dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
}
}
}
// 如果 amount下标的值没改变, 表示无法凑出
return dp[amount] > amount ? -1 : dp[amount];
}
}
第三题: 爬楼梯的最少成本
LeetCode: 剑指 Offer II 088. 爬楼梯的最少成本
描述:
数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。
每当爬上一个阶梯都要花费对应的体力值,一旦支付了相应的体力值,就可以选择向上爬一个阶梯或者爬两个阶梯。
请找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。
解题思路:
动态规划思路:
- 状态 F(i) : 表示爬到第i节楼梯所需要的最小花费
- 状态转移方程: F[i] = Math.min(F[i-2],F[i-1])+cost[i];
- 初始状态: F(0) = cost[0];F(1) = cost[1]
- 返回结果: Math.min( F(len-1) , F(len-2) )
因为这里可以跳1步或者2步, 所以要判断前两个最小的花费, 然后加上当前花费
返回结果就要看 最后一个台阶和倒数第二个台阶谁小
代码实现:
class Solution {
public int minCostClimbingStairs(int[] cost) {
int[] dp = new int[cost.length];
// 初始化
dp[0] = cost[0];
dp[1] = cost[1];
for(int i = 2; i < cost.length; i++) {
dp[i] = Math.min(dp[i-2],dp[i-1])+cost[i];
}
return Math.min(dp[cost.length-1],dp[cost.length-2]);
}
}
第四题: 翻转字符
LeetCode: 剑指 Offer II 092. 翻转字符
描述:
如果一个由 ‘0’ 和 ‘1’ 组成的字符串,是以一些 ‘0’(可能没有 ‘0’)后面跟着一些 ‘1’(也可能没有 ‘1’)的形式组成的,那么该字符串是 单调递增 的。
我们给出一个由字符 ‘0’ 和 ‘1’ 组成的字符串 s,我们可以将任何 ‘0’ 翻转为 ‘1’ 或者将 ‘1’ 翻转为 ‘0’。
返回使 s 单调递增 的最小翻转次数。
解题思路:
- 遍历字符串s
- 判断当前字符是否为0
如果为0, 就记录zero = Math.min(one, zero+1)
因为当初始状态,没有1的时候, 就开始记录0会浪费,要记录当1有的时候. 这里使用min的方法来判断了.
如果为1, 就记录one++
遍历结束, 比较zero
和one
的大小, 返回较小的
代码实现:
第五题: 粉刷房子
LeetCode: 剑指 Offer II 091. 粉刷房子
描述:
假如有一排房子,共 n 个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。
当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3 的正整数矩阵 costs 来表示的。
例如,costs[0][0]
表示第 0 号房子粉刷成红色的成本花费;costs[1][2]
表示第 1 号房子粉刷成绿色的花费,以此类推。
请计算出粉刷完所有房子最少的花费成本。
解题思路:
题目中有要求: 粉刷所有的房子并且使其相邻的两个房子颜色不能相同
cost[i][0] = cost[i-1][1]+cost[i-1][2]
, 以这样的方式,计算每层的使用当前颜色的最小值.
返回最后一层中, 最小的那一个
代码实现:
class Solution {
public int minCost(int[][] costs) {
for(int i = 1; i < costs.length; i++){
costs[i][0] += Math.min(costs[i-1][1],costs[i-1][2]);
costs[i][1] += Math.min(costs[i-1][0],costs[i-1][2]);
costs[i][2] += Math.min(costs[i-1][1],costs[i-1][0]);
}
return Math.min(costs[costs.length-1][0],Math.min(costs[costs.length-1][1],costs[costs.length-1][2]));
}
}
第六题: 房屋偷盗
LeetCode: 剑指 Offer II 089. 房屋偷盗
描述:
一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响小偷偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组 nums ,请计算 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
解题思路:
动态规划思路:
- 状态 F(i) : 表示盗窃到i下标时的最高金额
- 状态转移方程: F[i] = Math.max( F[i-2] + nums[i], F[i-1]) ;
- 初始状态: F(0) = nums[0], F(1) = Math.max(nums[0],nums[1])
- 返回结果: F(len-1)
代码实现:
class Solution {
public int rob(int[] nums) {
if(nums.length == 1) return nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0],nums[1]);
for(int i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[nums.length-1];
}
}