一、爬楼梯
题目:
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
思路:
采用动态规划的思想
当n=1时,有一种方法
当n=2时,有两种方法,即1和2
当n=3时,有三种方法,即1+1+1,1+2,2+1
当n=4时,有五种方法,即1+1+1+1,1+1+2,1+2+1,2+1+1,2+2
.............
由此可以总结出一个递推式,f(n) = f(n-1) + f(n-2)
可以发现,爬楼梯问题演变成个斐波那契数列的问题,代码就很好写了
public int climbStairs(int n) {
int[] dp = new int[n + 1]; // 创建一个数组 dp,长度为 n + 1,用于存储不同台阶数对应的方法数
dp[0] = 1; // 0 阶楼梯,只有一种方法:不爬
dp[1] = 1; // 1 阶楼梯,只有一种方法:爬一步到顶
// 循环计算从 2 阶到 n 阶的方法数
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2]; // 当前台阶数的方法数等于前一阶和前两阶方法数之和
}
return dp[n]; // 返回爬到 n 阶的方法数
}
具体分析:
-
数组定义与初始化:
int[] dp = new int[n + 1];
创建一个长度为n + 1
的整数数组dp
,用来存储到达每个台阶的不同方法数。数组下标表示台阶数,数组值表示到达该台阶的方法数。
-
初始条件:
dp[0] = 1;
0 阶楼梯只有一种方法,即不爬。dp[1] = 1;
1 阶楼梯只有一种方法,即爬一步到顶。
-
动态规划转移方程:
for (int i = 2; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; }
- 从 2 阶开始循环到 n 阶,计算每个台阶的方法数。
dp[i] = dp[i - 1] + dp[i - 2];
:当前台阶i
的方法数等于到达前一阶和前两阶的方法数之和。这是因为到达当前台阶可以从前一阶爬一步到达,或者从前两阶爬两步到达。
-
返回结果:
return dp[n];
返回存储在dp
数组中的到达第n
阶楼梯的方法数,即解决问题的答案。
二、四数相加
题目:
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
思路:
本题采用哈希表的方法,优先判断nums1+nums2中的值,再判断num3+nums4中的值,如果前者的值为i+j,后者的值为-(i+j),说明四个数组相加的值等于0
代码:
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res = 0; // 用于存储满足条件的组合数量
Map<Integer, Integer> map = new HashMap<>(); // 创建一个 HashMap,用于存储两个数组元素之和及其出现次数
// 第一对循环,统计 nums1 和 nums2 中元素的和及其出现次数
for (int i : nums1) {
for (int j : nums2) {
int sum = i + j; // 计算当前两个元素之和
map.put(sum, map.getOrDefault(sum, 0) + 1); // 将该和作为 key,出现次数作为 value 放入 map 中
}
}
// 第二对循环,统计 nums3 和 nums4 中元素的和,在 map 中查找是否存在相加为 0 的情况,并累加结果到 res 中
for (int i : nums3) {
for (int j : nums4) {
res += map.getOrDefault(0 - i - j, 0); // 查找 map 中是否有 -(i+j) 的键,并将其值累加到 res 中
}
}
return res; // 返回满足条件的组合数量
}
具体解释:
-
初始化变量:
res
:用于记录满足条件的四数之和为 0 的组合数量。map
:用于存储两个数组中元素之和及其出现次数的 HashMap。
-
第一对循环(外层循环):
- 遍历
nums1
中的每一个元素i
和nums2
中的每一个元素j
。 - 计算当前两个元素的和
sum = i + j
。 - 将
sum
作为 key,将其在map
中的出现次数增加 1。
- 遍历
-
第二对循环(内层循环):
- 遍历
nums3
中的每一个元素i
和nums4
中的每一个元素j
。 - 计算当前两个元素的和
-i - j
。 - 使用
map.getOrDefault(0 - i - j, 0)
查找map
中是否有-i - j
这个 key,如果有,则将其对应的值累加到res
中。
- 遍历
-
返回结果:
- 返回
res
,即满足四数之和为 0 的组合数量。
- 返回
拓展:
map.getOrDefault(key, defaultValue)
是 Java 中用于获取 Map 中指定 key 对应的值的方法。如果 Map 中包含指定的 key,则返回与该 key 关联的值;如果 Map 中不包含指定的 key,则返回 defaultValue。
参数解释:
- key:要在 Map 中查找的键。
- defaultValue:如果 Map 中不包含指定的 key,则返回的默认值。
使用示例:
假设有一个 Map map
,其中包含一些键值对:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 10);
map.put("banana", 20);
map.put("cherry", 30);
现在我们可以使用 getOrDefault
方法来获取指定键的值:
int count1 = map.getOrDefault("apple", 0); // 此时 count1 = 10
int count2 = map.getOrDefault("grape", 0); // 此时 count2 = 0,因为 "grape" 不在 Map 中,返回 defaultValue = 0
在上面的例子中:
map.getOrDefault("apple", 0)
返回键 "apple" 对应的值 10。map.getOrDefault("grape", 0)
返回键 "grape" 对应的默认值 0,因为 "grape" 在 Map 中不存在。
适用场景:
getOrDefault
方法通常在需要从 Map 获取值时使用,尤其是在不确定键是否存在时,可以提供一个默认值,避免因为键不存在而引发异常或返回 null 的情况。
今天的学习就到这里了