454四数相加
题目链接:454. 四数相加 II - 力扣(LeetCode)
思路:一开始想到了哈希表,先循环三次数组后,再使用哈希表,时间复杂度为n的立方。之后在视频启发下写出了利用两个哈希表的代码。空间复杂度较高。
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer,Integer> sum1=new HashMap<>();
HashMap<Integer,Integer> sum2=new HashMap<>();
int count=0;
for(int i:nums1){
for(int j:nums2){
int target=i+j;
sum1.put(target,sum1.getOrDefault(target,0)+1);
}
}
for(int i:nums3){
for(int j:nums4){
int target=i+j;
sum2.put(target,sum2.getOrDefault(target,0)+1);
}
}
Set<Integer> keys=sum1.keySet();
for(int key:keys){
int temp=-key;
if(sum2.containsKey(temp)){
count+=sum1.get(key)*sum2.get(temp);
}
}
return count;
}
}
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer,Integer> sum=new HashMap<>();
int count=0;
for(int i:nums1){
for(int j:nums2){
int temp=i+j;
sum.put(temp,sum.getOrDefault(temp,0)+1);
}
}
for(int i:nums3){
for(int j:nums4){
if(sum.containsKey(0-i-j)){
count+=sum.get(0-i-j);
}
}
}
return count;
}
}
383赎金信
和242类似,既可以用哈希表也可以用数组做。
哈希表
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
HashMap<Character,Integer> hm=new HashMap<>();
for(int i=0;i<magazine.length();i++){
char c=magazine.charAt(i);
hm.put(c,hm.getOrDefault(c,0)+1);
}
for(int i=0;i<ransomNote.length();i++){
char c=ransomNote.charAt(i);
if(hm.containsKey(c)){
hm.put(c,hm.get(c)-1);
if(hm.get(c)<0) return false;
}else{
return false;
}
}
return true;
}
}
数组
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] arr=new int[26];
for(char c:magazine.toCharArray()){
arr[c-'a']++;
}
for(char c:ransomNote.toCharArray()){
arr[c-'a']--;
}
for(int i=0;i<arr.length;i++){
if(arr[i]<0)return false;
}
return true;
}
}
15三数之和
难点在于如何排除重复元素,大致思路是先循环后二分查找。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n=nums.length;
Arrays.sort(nums);
List<List<Integer>> res=new ArrayList<List<Integer>>();
if(n<3)return null;
for(int i=0;i<n;i++){
if(nums[i]>0)return res;
if(i>0&&nums[i]==nums[i-1])continue;
int left=i+1;
int right=n-1;
while(left<right){
int sum=nums[i]+nums[left]+nums[right];
if(sum==0){
res.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){
right--;
}else if(sum<0){
left++;
}
}
}
return res;
}
}
18四数之和
方法一:递归
定义为long,是为了防止整数溢出。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
// 先对数组进行排序
Arrays.sort(nums);
// 调用函数
return nSum(nums,target,4,0);
}
// 对数组nums,从start索引开始,寻找n个元素使之和为target
public List<List<Integer>> nSum(int[] nums, long target,int n,int start){
int sz=nums.length;
// 定义结果
List<List<Integer>> res=new ArrayList<List<Integer>>();
// n至少为2,若数组长度小于n的个数则直接返回
if(n<2||sz<n)return res;
// basecase为2
if(n==2){
int lo=start,hi=sz-1;
while(lo<hi){
long sum=nums[lo]+nums[hi];
long left=nums[lo];
long right=nums[hi];
if(sum<target){
// 确保lo<hi,且若lo所指的元素和上一位元素相等,则移到下一位
while(lo<hi&&nums[lo]==left)lo++;
}else if(sum>target){
while(lo<hi&&nums[hi]==right)hi--;
}else{
// 将符合条件的两个元素放到结果中
// Arrays.asList()将数组改成集合类型,但是会报错java.lang.UnsupportedOperationException这是由Arrays.asList() 返回的是Arrays的内部类ArrayList, 而不是java.util.ArrayList。故将其转换为Arraylist
res.add(new ArrayList<>(Arrays.asList(nums[lo],nums[hi])));
// 继续排除重合的元素
while(lo<hi&&nums[lo]==left)lo++;
while(lo<hi&&nums[hi]==right)hi--;
}
}
}else{
for(int i=start;i<sz;i++){
// 对于n>2的情况,使用递归调用函数
List<List<Integer>> subres=nSum(nums,target-nums[i],n-1,i+1);
// 将元素加入到res中
for(List<Integer> arr:subres){
arr.add(nums[i]);
res.add(arr);
}
// 排除重复元素
while(i<sz-1&&nums[i]==nums[i+1])i++;
}
}
return res;
}
}
方法二:循环加二分
注意:排除重复元素的先后,+1、-1.
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
int n=nums.length;
Arrays.sort(nums);
List<List<Integer>> res=new ArrayList<>();
for(int i=0;i<n;i++){
if(nums[i]>target&&nums[i]>0)return res;
if(i>0&&nums[i]==nums[i-1]) continue;
for(int j=i+1;j<n;j++){
if(nums[i]+nums[j]>target&&nums[i]>0)return res;
if(j>i+1&&nums[j-1]==nums[j]) continue;
int left=j+1,right=n-1;
while(left<right){
int sum=nums[i]+nums[j]+nums[left]+nums[right];
if(sum==target){
res.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){
right--;
}else if(sum<target){
left++;
}
}
}
}
return res;
}
}