目录
题目链接:454. 四数相加 II - 力扣(LeetCode)
You are back it with all the good things in the world.
今日体会:HashMap、数组、双指针法解题的巧妙。
题目链接:454. 四数相加 II - 力扣(LeetCode)
使用哈希表来优化这个问题:
1. 用一个哈希表来存储
nums1[i] + nums2[j]
的所有可能结果及其出现次数;2. 遍历
nums3[k] + nums4[l]
的所有可能结果,并检查-(nums3[k] + nums4[l])
是否在哈希表中;3. 如果存在,则累加对应的次数。
class Solution454 {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int n = nums1.length;
HashMap<Integer, Integer> hashMap = new HashMap<>();
int count = 0;
// 遍历nums1和nums2的所有组合,并记录和出现的次数
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int sum = nums1[i] + nums2[j];
hashMap.put(sum, hashMap.getOrDefault(sum,0) + 1); // 如果指定的键在哈希表中存在,则返回对应的值;如果不存在,则返回指定的默认值0。
}
}
// 遍历nums3和nums4的所有组合,检查是否存在和为0的情况
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int sum = nums3[i] + nums4[j];
count += hashMap.getOrDefault(-sum,0);
}
}
return count;
}
}
- 时间复杂度:O(n^2)
题目链接:383. 赎金信 - 力扣(LeetCode)
思路1:可以使用一个数组来实现字符计数。因为题目中的字符都是小写字母,可以用一个长度为 26 的整型数组来表示每个字母的出现次数。
思路2:可以使用哈希表来记录 magazine
中每个字符的出现次数,然后检查 ransomNote
中的每个字符是否都在 magazine
中有足够的数量。
class Solution383 {
public boolean canConstruct(String ransomNote, String magazine) {
if (ransomNote.length() > magazine.length())
return false;
int[] arr = new int[26];
// 记录magazine里各个字符出现的次数
for (char c : magazine.toCharArray()) {
arr[c - 'a'] += 1;
}
// 检查ransomNote中每个字符是否都在magazine中有足够的数量
for (char c : ransomNote.toCharArray()) {
if (arr[c - 'a'] == 0) {
return false;
}
arr[c - 'a']--;
}
return true;
}
// 哈希表思路
public boolean canConstruct2(String ransomNote, String magazine) {
HashMap<Character, Integer> charCount = new HashMap<>();
// 统计 magazine 中每个字符的数量
for (char c : magazine.toCharArray()) {
charCount.put(c, charCount.getOrDefault(c, 0) + 1);
}
// 检查 ransomNote 中的每个字符是否都在 magazine 中有足够的数量
for (char c : ransomNote.toCharArray()) {
if (!charCount.containsKey(c) || charCount.get(c) == 0) {
return false;
}
charCount.put(c, charCount.get(c) - 1);
}
return true;
}
}
- 时间复杂度: O(n)
另 代码随想录 中:一些同学可能想,用数组干啥,都用map完事了,其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!
题目链接:15. 三数之和 - 力扣(LeetCode)
两层for循环就可以确定 a 和b 的数值了,可以使用哈希法来确定 0-(a+b) 是否在 数组里出现过,其实这个思路是正确的,但是有一个非常棘手的问题,就是题目中说的不可以包含重复的三元组。
这道题目使用哈希法并不十分合适,因为在去重的操作中有很多细节需要注意,在面试中很难直接写出没有bug的代码。
思路:故如图所示使用双指针法。首先将数组排序,然后遍历数组,对于每个元素,使用双指针在剩余部分寻找两个数使得三个数的和为0。为了避免重复的三元组,注意跳过重复的元素。
class Solution15 {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums); // 先排序 使用双指针法
List<List<Integer>> result = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if(i > 0 && nums[i] == nums[i-1]){
continue; // 跳过重复的元素
}
int left = i + 1, right = nums.length - 1;
while (left < right){
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0){
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 跳过重复的元素
while (left < right && nums[left] == nums[left + 1]){
left ++;
}
while (left < right && nums[right] == nums[right - 1]){
right --;
}
left ++;
right --;
} else if(sum < 0){
left ++;
} else {
right --;
}
}
}
return result;
}
}
题目链接:18. 四数之和 - 力扣(LeetCode)
思路:使用双指针方法,类似于三数之和问题。首先对数组进行排序,然后遍历数组,对每一对组合,使用双指针在剩下的部分寻找两个数使得四者之和等于目标值。
1. 外层的两个循环分别固定两个数
nums[i]
和nums[j];
2. 内层的双指针
left
和right
在剩余的数组部分寻找另外两个数使得四个数的和等于目标值;3. 通过跳过重复的元素来避免重复的四元组。
class Solution18 {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums); // 排序 再用双指针法
List<List<Integer>> result = new ArrayList<>();
int n = nums.length;
for (int i = 0; i < n - 3; i++) { // 思考为什么是n-3?
if (i > 0 && nums[i] == nums[i - 1])
continue;
for (int j = i + 1; j < n - 2; j++) { // 思考为什么是n-2?
if (j > i + 1 && nums[j] == nums[j - 1]) // 去重
continue;
int left = j + 1, right = n - 1;
while (left < right){
long sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target){
result.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
// 去重
while (left < right && nums[left] == nums[left + 1]){
left ++;
}
while (left < right && nums[right] == nums[right - 1]){
right -- ;
}
left ++;
right --;
} else if (sum < target) {
left ++;
} else {
right --;
}
}
}
}
return result;
}
}
- 时间复杂度:O(n^3)
回顾双指针法题目
最后在这里回归一下使用了双指针法的几道题目:
双指针法将时间复杂度:O(n^2)的解法优化为 O(n)的解法。也就是降一个数量级,题目如下:
链表相关双指针题目:
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)