● 454.四数相加II
题目链接: https://leetcode.cn/problems/4sum-ii/
解题思路:
第一轮遍历, 记录数组 nums1 和数组 nums2对应元素 之和 , 以及这样的和出现的次数, 记录在hashmap 中.
第二轮遍历,累加 nums3 和数组 nums4 对应元素 之和num,判断 数字0 与 和 num之前的差值,是否在hashmap 中 存在. 如果存在,记录次数,累加这些次数,进行返回.
参考答案:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
int index = 0;
for (int mum1 : nums1) {
for (int mum2 : nums2) {
if (hashMap.containsKey(mum1 + mum2)) {
hashMap.put(mum1 + mum2, hashMap.get(mum1 + mum2) + 1);
} else {
hashMap.put(mum1 + mum2, hashMap.getOrDefault(mum1 + mum2, 1));
}
}
}
int num = 0;
for (int mum3 : nums3) {
for (int mum4 : nums4) {
if (hashMap.containsKey(0 - (mum3 + mum4))) {
num += hashMap.get(0 - (mum3 + mum4)) ;
}
}
}
return num;
}
}
● 383. 赎金信
题目链接: https://leetcode.cn/problems/ransom-note/
解题思路:
int num1 = 'a'; num1的值为97, 阿斯克码表的值.
int num2 = 'b' - 'a'; num2的值为1
int num2 = 'c' - 'a'; num2的值为2
创建一个长度为26 (小写字母的个数) 的数组.
小写字母,相比字母的顺序(a,b,c,d,e.......), 对应在阿斯克码表中的值是连续递增的.
单独的字符相减得到的数字,把他们映射到数组的索引位置上,根据映射到的次数,做增加操作.这样就有了字符串magazine的各个字母出现的位置 和 出现次数的对应关系了.
比如 'b'出现第一次在数字中 arr['b'-'a']++ ,也就是arr[1]=1.
再去遍历字符串ransomNote,映射到对应的次数,做减少次数的操作,抵消magazine之前的操作.
最后遍历数组,如果存在元素的值不为空,说明 字符串s 和t中存在字母出现的次数不一样,返回false; 否则true.
参考答案:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
char[] chars = ransomNote.toCharArray();
int[] arr = new int[26];
for (char char1 : chars) {
arr[char1-'a']++;
}
char[] chars2 = magazine.toCharArray();
for (char char2 : chars2) {
arr[char2-'a']--;
}
for (int num : arr) {
if(num>0){
return false;
}
}
return true;
}
}
● 15. 三数之和
题目链接: https://leetcode.cn/problems/3sum
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
解题思路:
用双指针法来实现, 遍历数组, 声明三个变量 int i ; int left=i+1 ; int right = nums.length - 1
三个索引 i ; left ; right 处的值相加的和和 目标数字 0 相比,
i不变的时候,在,满足 left< right的情况,while 循环.
如果>0 ,右边指针right--;
如果<0 ,左边指针left++ ;
如果== 0,把对应数组的值记录在集合里面.
接下来分析,去重的问题.
题目要求: 数组不能重复; i ; left ; right 三个值也不能重复
i 的去重:
本题目是,先固定i,先移动 left 和right两个指针,来寻找满足和为0的三个值.
为什么是: nums[i] == nums[i -1] 而不是nums[i] == nums[i +1]
一组特殊的测试用例: [ -1,0,1 ] 排序后: [ -1,-1,0 ]
如果用后者的逻辑,这桑热书实际是满足要求的,数据不重复,但是数组内的元素可以是不同索引处的重复,用后面这个逻辑,就会把这组数据错过.
if (i>0 && nums[i] == nums[i -1]) {
continue;
}
left 和 right的去重:
(1). 三个值累加和 大于 或者 小于 0的时候,不满足等于条件,即使 nums[right] == nums[right - 1] 或者nums[left] == nums[left +1], 从 left 遍历到 left +1 或者从right 遍历到 right - 1 ,同样不满足等于0的条件,此时会 right-- 或者 left++ ,不用额外去重.
(2) . 三个值累加和 等于 0的时候,满足等于条件.
此时,如果 遇到 nums[right] == nums[right - 1] 或者nums[left] == nums[left +1]的情况,就要right-- 或者 left++. 此操作,在把满足条件的三个值存到集合中的代码 逻辑 之后.
参考答案:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
int sum = 0;
for (int i = 0; i < nums.length; i++) {
int left = i + 1;
int right = nums.length - 1;
if (i>0 && nums[i] == nums[i -1]) {
continue;
}
while (left < right) {
sum = nums[i] + nums[left] + nums[right];
if (sum > 0) {
right--;
} else if (sum < 0) {
left++;
} else {
list.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (right > left && nums[right] == nums[right - 1]) {
right--;
}
while (right > left && nums[left] == nums[left +1]) {
left++;
}
right--;
left++;
}
}
}
return list;
}
}
● 18. 四数之和
题目链接: https://leetcode.cn/problems/4sum/
解题思路:
这个题目时在三数之和的基础上 变化了一下,思路还是相似的.
原来是一次for 循环, 遍历时的索引 i , 和 left ,right 三个变量对应处的数组的值,累加求和.
原来是对 i,和 left ,right 分别去重.
现在需要多一次 for循环,遍历时的索引 i , j, 和 left ,right 四个变量对应处的数组的值,累加求和.
现在是对 i, j 和 left ,right 分别去重.
参考答案:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> lists = new ArrayList<>();
long num = 0;
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if(i>0 && nums[i]==nums[i-1]){
continue;
}
if(j >i + 1 && nums[j]==nums[j-1]){
continue;
}
int left = j + 1;
int right = nums.length - 1;
while (left < right) {
num = (long)nums[left] + nums[right] + nums[i] + nums[j];
if (left < right && num > target) {
right--;
} else if (left < right && num < target) {
left++;
} else {
lists.add(Arrays.asList(nums[left], nums[right], nums[i], nums[j]));
while (left<right && nums[left]==nums[left+1]){
left++;
}
while (left<right && nums[right]==nums[right-1]){
right--;
}
right--;
left++;
}
}
}
}
return lists;
}
}