2023.3.21 四数相加Ⅱ
由于题目只需要求出有多少个数组能够满足要求即可,所以我们可以直接使用哈希表,先储存前两个数组的元素和的信息,令元素和为key,值value存放元素和出现的次数。随后在根据后两个数组中的元素和来判断哈希表中是否有对应的数,如果有,将value计入结果中即可。
关键点,要想到把多个组别拆分为两组,一组计入哈希表,另一组根据要求结果计算出需要的值再哈希表中进行查找。
之前都是遇到的两个组的情况,现在有四个组,突然不知道咋做了。。。没想到分段处理。
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer> hashMap = new HashMap<>();
int res = 0;
//双重循环记录两个数组相加的结果
for(int x : nums1){
for(int y : nums2){
int add = x+y;
hashMap.put(add,hashMap.getOrDefault(add,0)+1);
}
}
for(int x : nums3){
for(int y : nums4){
int target = 0-(x+y);
if(hashMap.containsKey(target)){
res += hashMap.get(target);
}
}
}
return res;
}
}
2023.3.21 赎金信
由于magazinez中的每个字符只能在ransomNote中使用一次
所以我们的magazine长度至少要等于ransomNote。
随后我们将magazine中出现的英文字母记录进数组中,
方法一:利用数组记录信息
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if(magazine.length() < ransomNote.length()){
return false;
}
int[] res = new int[26];
for(int i = 0;i<magazine.length();i++){
res[magazine.charAt(i)-'a']++;
}
for(int i = 0;i<ransomNote.length();i++){
res[ransomNote.charAt(i)-'a']--;
}
for(int x : res){
if(x<0){
return false;
}
}
return true;
}
}
方法二:哈希表
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if(magazine.length() < ransomNote.length()){
return false;
}
Map<Character,Integer> hashMap = new HashMap<>();
for(int i = 0;i<magazine.length();i++){
char c = magazine.charAt(i);
hashMap.put(c,hashMap.getOrDefault(c,0) + 1);
}
for(int i = 0;i<ransomNote.length();i++){
char c = ransomNote.charAt(i);
hashMap.put(c,hashMap.getOrDefault(c,0) - 1);
if(hashMap.get(c) < 0){
return false;
}
}
return true;
}
}
2023.3.21 三数之和
由于题目要求我们求出三个元素满足其和为0,它并不需要我们求出元素的下标,因此我们可以对数组元素进行排序处理,随后使用指针对其进行循环判断即可。
如当我们对数组排序后,令i为数组第一个元素,j为i的右侧元素,k为数组最后一个元素,
如果nums[i]+nums[j]+nums[k]>0,说明我们需要k元素大了,需要向左移动k的位置
同理,如果nums[i]+nums[j]+nums[k]
当满足nums[i]+nums[j]+nums[k] = 0时,记录List中即可。
同时,题目要求我们结果中不能出现重复的三元组,这意味着我们的结果中数组元素不能用相同值。
首先考虑i的去重,由于i是向右移动的,当其值与左侧值相同时,由于左侧的元素已经做过一次判断,所以这次的元素不需要在做判断了,直接continue。
j的去重,j也是向右移动的,当j与j的左侧值相同时,直接令j继续右移即可。
k的去重,k是向左移动的,当k的值与k右侧的值相同时说明,k的值已经做过一次判断,继续左移。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//新建结果List
List<List<Integer>> res = new ArrayList<>();
//对数组排序
Arrays.sort(nums);
//开始循环遍历
for(int i = 0;i<nums.length-2;i++){
//由于数组已经进行过一次排序,因此当nums[i]>0时,此时已经无法满足三个数相加为0的要求了,直接返回结果
if(nums[i] > 0){
return res;
}
//对i去重
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
int j = i + 1;
int k = nums.length-1;
while(j < k){
int sum = nums[i] + nums[j] + nums[k];
if(sum > 0){//k需要向左移动
k--;
}
else if(sum < 0){//j需要向右移动
j++;
}
else{//得到结果
res.add(Arrays.asList(nums[i],nums[j],nums[k]));
//得到结果后需要继续移动指针,此时有可能存在重复结果,即k的左侧值与k相同,j的右侧值与j相同,因此我们在这里需要做去重处理,否则可能会有重复的结果。
while(j < k && nums[k-1] == nums[k]) k--;
while(j < k && nums[j+1] == nums[j]) j++;
//不存在重复元素也需要对j和k移动,将k左移,j右移,不能只移动一个,因为如果不是重复元素,必然不会有等于0的结果
k--;
j++;
}
}
}
return res;
}
}
2023.3.21 四数之和
多了一个元素要如何遍历?,使用双重循环?借鉴三数之和的思路?
错误代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
//对数组排序
Arrays.sort(nums);
for(int a = 0;a < nums.length - 3;a++){
if(nums[a] > target){
return res;
}
if(a > 0 && nums[a] == nums[a-1]){
continue;
}
for(int b = a + 1;b < nums.length - 2;b++){
//nums[b]的去重条件
if(b> a+1 && nums[b] == nums[b-1]){
continue;
}
int c = b+1;
int d = nums.length-1;
while(c < d){
int sum = nums[a] + nums[b] + nums[c] + nums[d];
if(sum > target){
d--;
}
else if(sum<target){
c++;
}
else{
res.add(Arrays.asList(nums[a],nums[b],nums[c],nums[d]));
while(c < d && nums[d-1] == nums[d]) d--;
while(c < d && nums[c+1] == nums[c]) c++;
d--;
c++;
}
}
}
}
return res;
}
}
这里的nums[a] > target判断条件有问题,因为不是三数之和为0的条件了,如果target为负数,即使nums[a]>target,也是可能有结果的。所以我们的条件应该是nums[a]>0 并且nums[a] > target时,就可以退出了。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
//对数组排序
Arrays.sort(nums);
for(int a = 0;a < nums.length - 3;a++){
if(nums[a] > 0 && nums[a] > target){
return res;
}
if(a > 0 && nums[a] == nums[a-1]){
continue;
}
for(int b = a + 1;b < nums.length - 2;b++){
//nums[b]的去重条件
if(b> a+1 && nums[b] == nums[b-1]){
continue;
}
int c = b+1;
int d = nums.length-1;
while(c < d){
int sum = nums[a] + nums[b] + nums[c] + nums[d];
if(sum > target){
d--;
}
else if(sum<target){
c++;
}
else{
res.add(Arrays.asList(nums[a],nums[b],nums[c],nums[d]));
while(c < d && nums[d-1] == nums[d]) d--;
while(c < d && nums[c+1] == nums[c]) c++;
d--;
c++;
}
}
}
}
return res;
}
}