该题与两数之和类似,由于结果只要返回符合条件的元组数,所以可以将四个数组看成两个大组,用一个map来记录两个大组中两个数组所有元素的可能的和以及出现的次数,然后再通过两个for循环来遍历另外一个大组中的两个数组元素,与map中记录的和进行相加,若相加等于target值,则返回map中记录的次数。
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer,Integer> map=new HashMap<>();
int sumcount=0;
for(int i=0;i<nums1.length;i++){
for(int j=0;j<nums2.length;j++){
int sum=0;
sum=nums1[i]+nums2[j];
int count=0;
if(map.containsKey(sum)){
int value;
value=map.get(sum);
value++;
map.put(sum,value);
}else{
count++;
map.put(sum,count);
}
}
}
for(int p=0;p<nums3.length;p++){
int sum1=0;
for(int q=0;q<nums4.length;q++){
sum1=nums3[p]+nums4[q];
if(map.containsKey(0-(sum1))){
sumcount+=map.get(0-(sum1));
}
}
}
return sumcount;
}
}
该题与有效字母异位词类似,都是小写字母,元素大小有限,可以通过下标映射使用hash数组。这里使用哈希数组映射ransomNote中的字母,与magazine字符串进行判断,若ransomNote中的字母在magazine字符串中出现过,则将该位置减1.最后若哈希数组中所有元素为0,则符合条件。
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] arr=new int[26];
for(int i=0;i<ransomNote.length();i++){ //先将ransomnote字符串映射到数组中
arr[ransomNote.charAt(i)-'a']++;
}
for(int j=0;j<magazine.length();j++){ //遍历magazine字符串,看其是否包含
if(arr[magazine.charAt(j)-'a']!=0){ //ransomnote字符串
arr[magazine.charAt(j)-'a']--;
}
}
for(int p=0;p<arr.length;p++){
if(arr[p]!=0){
return false;
}
}
return true;
}
}
这里三数之和有去重的要求,使用哈希法会比较麻烦,这里又是使用双指针的解法。首先将数组进行排序,以数组A为例。A[i]为起点,A[i+1]为左指针起点,A[size-1]为右指针起点位置。通过A[i]+A[left]+A[right]与target进行比较,若小了,则将左指针右移,若大了,则将右指针向左移。直到找到符合条件的左右指针。然后再接着移动i进行新的一轮查找。这里剪枝和去重操作见代码随想录讲解。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result=new ArrayList<>();
List<Integer> res=new ArrayList<>();
quicksort(nums,0,nums.length-1);
if(nums[0]>0){
return result;
}
for(int i=0;i<nums.length-1;i++){
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int left=i+1;
int right=nums.length-1;
while(left<right){
int sum=nums[i]+nums[left]+nums[right];
if(sum<0){
left++;
}else if(sum>0){
right--;
}else{
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
while(left<right&&nums[left]==nums[left+1]){
left++;
}
left++;
while(left<right&&nums[right]==nums[right-1]){
right--;
}
right--;
}
}
}
return result;
}
public void quicksort(int[] nums,int start,int end){
if(start>=end){
return ;
}
int p=parition(nums,start,end);
quicksort(nums,start,p-1);
quicksort(nums,p+1,end);
}
public int parition(int[] nums,int start,int end){
int left=start;
int right=end;
int privot=nums[start];
int temp;
while(left!=right){
while((nums[right]>privot)&&(left<right)){
right--;
}
while((nums[left]<=privot)&&(left<right)){
left++;
}
if(left<right){
temp=nums[left];
nums[left]=nums[right];
nums[right]=temp;
}
}
nums[start]=nums[left];
nums[left]=privot;
return left;
}
}
这题与三数之和类似,多加入一个for循环,但是里面的剪枝操作有些区别,二级循环中的剪枝操作只能是退出当前循环。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result=new ArrayList<>();
Arrays.sort(nums);
for(int k=0;k<nums.length;k++){
if(nums[k]>0&&nums[k]>target){ //剪枝操作
return result;
}
if(k>0&&nums[k]==nums[k-1]){ //去重操作
continue;
}
for(int i=k+1;i<nums.length;i++){
if(target>0&&nums[k]+nums[i]>target){ //剪枝操作
break; //这里只是退出当前二级循环
}
if(i>k+1&&nums[i]==nums[i-1]){ //去重操作
continue;
}
int l=i+1;
int r=nums.length-1;
while(l<r){
int sum=nums[k]+nums[i]+nums[l]+nums[r];
if(sum<target){
l++;
}else if(sum>target){
r--;
}else{
result.add(Arrays.asList(nums[k],nums[i],nums[l]
,nums[r]));
while(l<r&&nums[r]==nums[r-1]){
r--;
}
r--;
while(l<r&&nums[l]==nums[l+1]){
l++;
}
l++;
}
}
}
}
return result;
}
}