四数相加II
题目链接
视频链接
学透哈希表,map使用有技巧!LeetCode:454.四数相加II
思路:
1.定义一个map存储数组A,数组B中两数和的数值以及出现的次数
2.定义count储存答案
3.遍历数组C和数组D的两束和,然后在map中去找 -(nums3[i]+nums4[j])
4.如果可以找到,count+=对应的出现次数
代码:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int count=0;
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums1.length ; i++) {
for (int j = 0; j < nums2.length ; j++) {
//统计nums1+nums2两数和以及出现次数,默认为0
int sum=nums1[i]+nums2[j];
map.put(sum,map.getOrDefault(sum,0)+1);
}
}
for (int i = 0; i < nums3.length ; i++) {
for (int j = 0; j < nums4.length ; j++) {
//遍历数组C和数组D的两束和,然后在map中去找 -(nums3[i]+nums4[j])
int sum1=nums3[i]+nums4[j];
if(map.containsKey(-sum1)){
count+=map.get(-sum1);
}
}
}
return count;
}
}
赎金信
题目链接:
思路:
类似于 LeetCode_242同样用数组记录magazine中各个字符出现的次数,然后遍历ransomNote
字符出现一次就减一次,最后遍历数组,若元素小于0 说明magazine中某个字符不够用就无法完成赎金信 的书写
代码:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if (ransomNote.length() > magazine.length()) {
return false;
}
// 定义一个哈希映射数组
int[] record = new int[26];
// 遍历
for(char c : magazine.toCharArray()){
record[c - 'a'] += 1;
}
for(char c : ransomNote.toCharArray()){
record[c - 'a'] -= 1;
}
// 如果数组中存在负数,说明ransomNote字符串总存在magazine中没有的字符
for(int i : record){
if(i < 0){
return false;
}
}
return true;
}
}
map写法(消耗内存大)
public static boolean canConstruct(String ransomNote, String magazine) {
HashMap<Character, Integer> map_1 = new HashMap<>();
HashMap<Character, Integer> map_2 = new HashMap<>();
char[] charArray_1 = ransomNote.toCharArray();
char[] charArray_2 = magazine.toCharArray();
for (int i = 0; i <charArray_1.length ; i++) {
map_1.put(charArray_1[i],map_1.getOrDefault(charArray_1[i],0)+1);
}
for (int i = 0; i <charArray_2.length ; i++) {
map_2.put(charArray_2[i],map_2.getOrDefault(charArray_2[i],0)+1);
}
for (int i = 0; i <map_1.size() ; i++) {
if(!(map_2.size()>=map_1.size()&&map_1.containsKey(charArray_1[i])&&map_2.containsKey(charArray_1[i])&&map_1.get(charArray_1[i])<=map_2.get(charArray_1[i]))){
return false;
}
}
return true;
}
三数之和
题目链接:
视频链接:
思路:
双指针法:
拿这个nums数组来举例,首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i],b = nums[left],c = nums[right]。
接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
注意点:
题目要求不能有重复的三元组出现,所以需要对a,b,c进行去重操作
代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new LinkedList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length ; i++) {
if(nums[i]>0){
return ans;
}
if(i>0&&nums[i]==nums[i-1]){//重点:
/*
如果我们的写法是 这样:
if (nums[i] == nums[i + 1]) { // 去重操作
continue;
}
那我们就把 三元组中出现重复元素的情况直接pass掉了。 例如{-1, -1 ,2} 这组数据,当遍历到第一个-1 的时候,判断 下一个也是-1,那这组数据就pass了。们要做的是 不能有重复的三元组,但三元组内的元素是可以重复的!
所以这里是有两个重复的维度。那么应该这么写:
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
这么写就是当前使用 nums[i],我们判断前一位是不是一样的元素,在看 {-1, -1 ,2} 这组数据,当遍历到 第一个 -1 的时候,只要前一位没有-1,那么 {-1, -1 ,2} 这组数据一样可以收录到 结果集里。
*/
continue;//对a进行去重,因为对数组进行了排序,如果前面选过一次a ,那么就不选了,避免重复
}
int left=i+1;
int right= nums.length-1;
while (left<right) {
int sum = nums[i] + nums[left] + nums[right];
if(sum>0){
right--;
}
else if(sum<0){
left++;
}else {
ans.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 ans;
}
}
四数之和
题目链接:
视频链接:
四数之和,和15.三数之和 (opens new window)是一个思路,都是使用双指针法, 基本解法就是在15.三数之和 (opens new window)的基础上再套一层for循环。
但是有一些细节需要注意,例如: 不要判断nums[k] > target
就返回了,三数之和 可以通过 nums[i] > 0
就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。比如:数组是[-4, -3, -2, -1]
,target
是-10
,不能因为-4 > -10
而跳过。但是我们依旧可以去做剪枝,逻辑变成nums[i] > target && (nums[i] >=0 || target >= 0)
就可以了
代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0 && nums[i] > target) {
return ans;//剪枝
}
if (i > 0 && nums[i - 1] == nums[i]) { // 对nums[i]去重
continue;
}
for (int j = i+1; j < nums.length; j++) {
if (j > i + 1 && nums[j - 1] == nums[j]) { // 对nums[j]去重
continue;
}
int left = j + 1;
int right = nums.length - 1;
while (left < right) {
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if (sum > target) {
right--;
} else if (sum < target) {
left++;
} else {
ans.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
// 对nums[left]和nums[right]去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
left++;
right--;
}
}
}
}
return ans;
}
}
总结
。