和为定值的子数组

先分享第一反应想到的解法,因为只要求四个元素相加和为一目标值,可以先定下一个值,将问题简化为求三个数和为固定值,然后再固定一个值,转为两个数和为固定值,以此来找到定值为K的四个元素的所有组合。

有一个需要注意的点,避免重复,给定的数组中可能会有相同值的数,为了避免最后得到重复的组合,我们要先将数组排序,这样遇到重复的跳过即可。

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class fixedSum{
	private static int NUM_AMOUNT=4;
	private static List<List<Integer>>fixedSum(int[]nums,int target){
		List<List<Integer>>res=new ArrayList<>();
		//如果数组长度不足4,返回空结果
		if(nums==null||nums.length<NUM_AMOUNT) {
		return res;
		}
		//对数组进行排序
		Arrays.sort(nums);
		int len=nums.length;
		//先找一个数
		for(int i=0;i<len-NUM_AMOUNT+1;i++) {
			//对于重复值就不再计算
			if(i>0&&nums[i]==nums[i-1]) {
				continue;
			}
			//对于连续的四个数相加如果大于TARGET,则之后不可能再出现四元组,跳出循环
			if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) {
				break;
			}
			//如果当前值加上最大的三个数都小于target,那就跳出此轮循环
			if(nums[i]+nums[len-3]+nums[len-2]+nums[len-1]<target) {
				continue;
			}
			
			//找第二个数
			for(int j=i+1;j<len-NUM_AMOUNT+2;j++) {
				if(j>i+1 &&nums[j]==nums[j-1]) {
					continue;
				}
				//连续的三个数相加如果大于target,跳出循环
				if(nums[i]+nums[j]+nums[j+1]+nums[j+2]>target) {
					break;
				}
				//加上最大的两个数如果小于target,跳出此轮循环
				if(nums[i]+nums[j]+nums[len-2]+nums[len-1]<target) {
					continue;
				}
				
			//将三数之和问题转化为两数之和,用二分法解决
				int l=j+1,r=len-1;
				while(l<r) {
					int sum=nums[i]+nums[j]+nums[l]+nums[r];
					if(sum==target) {
						res.add(Arrays.asList(nums[i],nums[j],nums[l],nums[r]));
						
						while(l<r &&nums[l]==nums[l+1])
						{
							l++;
						}
						l++;
						while(l<r &&nums[r]==nums[r-1]) {
							r--;
						}
						r--;
					}
					else if(sum<target){
						l++;
					}
					else {
						r--;
					}
				}
			}
			
		}
		
		
		return res;
	}
	
	
	public static void main(String []args) {
		Scanner input=new Scanner(System.in);
		int t=input.nextInt();
        //while(t-->0)
		for(int i=0;i<t;i++) {
			int n=input.nextInt();
			int target=input.nextInt();
			int []nums=new int[n];
			for(int j=0;j<n;j++) {
				nums[j]=input.nextInt();
			}
			List<List<Integer>>res=fixedSum(nums,target);
			print(res);
		}
	}
	
	private static void print(List<List<Integer>>res) {
		for(List<Integer>subArr:res) {
			for(Integer element:subArr) {
				System.out.print(element+" ");
			}
			System.out.print("$");
		}
		System.out.println();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值