454.四数相加II
文档讲解:四数相加II
视频链接:代码随想录-四数相加II
状态:ok
思路:
该题和昨天的两数之和感觉比较类似;此题是每两个数组进行操作;
1、先定义一个map集合,key存储nums1[i]和nums2[j]的和,value存储nums1[i]+nums2[j]对应出现的次数;
2、然后遍历nums3和nums4两个数组,判断key = 0-(nums3[i]+nums4[j])是否存在于map中,如果存在,则计数count+map.get(key);
代码:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer, Integer> map12 = new HashMap<>();
for (int i = 0; i < nums1.length; i++) {
for (int j = 0; j < nums2.length; j++) {
int sumAB = nums1[i] + nums2[j];
if (!map12.containsKey(sumAB)) {
map12.put(sumAB, 1);
} else {
Integer num = map12.get(sumAB);
map12.put(sumAB, ++num);
}
}
}
int count = 0;
for (int i : nums3) {
for (int j : nums4) {
int sumAB = 0 - i - j;
if (map12.containsKey(sumAB)) {
count += map12.get(sumAB);
}
}
}
return count;
}java
}
383.赎金信
文档讲解:赎金信
状态:此题类似于昨天写的有效的字母异位词那一题,昨天刷过哪一题之后,这题写出来了;
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
HashMap<Integer, Integer> magaMap = new HashMap<>();
for (int i = 0; i < magazine.length(); i++) {
int charNum = magazine.charAt(i) - 'a';
if (magaMap.containsKey(charNum)) {
magaMap.put(charNum, (magaMap.get(charNum) + 1));
} else {
magaMap.put(charNum, 1);
}
}
for (int i = 0; i < ransomNote.length(); i++) {
int charNum = ransomNote.charAt(i) - 'a';
if (!magaMap.containsKey(charNum) || magaMap.get(charNum) <= 0) {
return false;
}
magaMap.put(charNum, (magaMap.get(charNum)-1));
}
return true;
}
}
15.三数之和
文档讲解:三数之和
视频链接:代码随想录-三数之和
状态:看完讲解后实现了,这题有难度
思路:
1、先对数组进行排序(因为题目没有要求返回对应的数组下标,所以可以打乱原先的数据顺序);
2、排序之后,先用i进行数组遍历,然后定义left=i+1,right=nums.length-1;方便进行三元组查找,left和right定义在两侧,是为了进行数据查找,当num[i]+num[left]+num[right]>0时,将right往里缩(即right–),反之,left往里缩(即left++);
3、对遍历进行去重和收集操作,这一步非常关键;去重操作例如:“nums[i] == nums[i - 1]”,为什么是与前一个元素比较,而不是"nums[i] == nums[i + 1]“与下一个元素比较呢?问题在于,如果你与下一个元素比较后直接continue,那么就相当于不收集这个元素了,自己体会;再例如:当nums[i] + nums[left] + nums[right] = 0时,收集完三元组后,对num[left]和num[right]去重,即操作"nums[right] == nums[right - 1]”,“nums[left] == nums[left + 1]”;
代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
//非常关键的一步,先将数组排序
Arrays.sort(nums);
//使用双指针完成三数之和
for (int i = 0; i < nums.length; i++) {
//如果nums[i]大于0了,则后边的再num[left]+num[right]就没有意义了
if (nums[i] > 0) {
return result;
}
//去重操作,对i即对三元组第一个元素进行去重
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
//定义双指针遍历查找是否存在 nums[i] + nums[left] + nums[right] = 0
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum > 0) { //说明数据大了,需要right指针往里缩
right--;
} else if (sum < 0) { //说明数据小了,left指针要往上加
left++;
} else { //此时等于0了,可以开始收集结果集了,但是这里又要考虑去重的问题,非常关键
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (left < right && nums[right] == nums[right - 1])
right--;
while (left < right && nums[left] == nums[left + 1])
left++;
right--;
left++;
}
}
}
return result;
}
}
18.四数之和*
文档讲解:四数之和
视频链接:代码随想录-四数之和
状态:禁止套娃🪆
思路:
1、这题可以看成是三数之和的衍生题,但是此题需要注意的是,三数之和要求target=0,而此题target可能是任意数,所以,在对循环进行枝剪时,要注意考虑target和nums[k]和为负数的情况;
代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
//排序
Arrays.sort(nums);
//此题注意有负数的情况,因为三数之和时要求和为0,所以第一层可以做枝剪
for (int k = 0; k < nums.length; k++) {
//第一层枝剪
if (nums[k] > 0 && nums[k] > target) {
return result;
}
//k位置第一个元素去重
if (k > 0 && nums[k] == nums[k-1]) {
continue;
}
for (int i = k+1; i < nums.length; i++) {
if (i > k+1 && nums[i] == nums[i-1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[k] + nums[i] + nums[left] + nums[right];
if (sum > target) {
right--;
} else if (sum < target) {
left++;
} else {
result.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));
while (left < right && nums[right] == nums[right-1]) {
right--;
}
while (left < right && nums[left] == nums[left+1]) {
left++;
}
right--;
left++;
}
}
}
}
return result;
}
}