K Sum

这是一个系列的题目,在LeetCode上都有,首先是2Sum,也就是最简单的题目。题目如下:

Given an array of integers, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution.

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

题意:就是给定一个数组,然后给定一个target,求在这个数组中的任意两个数的和为这个target值,然后得到这两个数字的下标值,并返回。当然要求这两个下标值必须是按照从小到大来输出的。此题在《剑指Offer》一书中也有提到,先排序,但是因为这题要注意,因为它要求返回的是原始的那个数组的元素情况,而并不是按从小到大排完序之后的那个位置,所以在一开始需要将原始数组复制一份,然后再对数组进行排序,采用Arrays.sort()方法。采用两个指针,分别指向头和尾,将这两个数字相加,如果发现正好,那么这两个数就是我们要找的那两个数,否则如果比它大,那么我们将尾巴的那个数字的下标减1,继续循环;如果比它小,那么我们可以将头的那个数字的下标加1,继续循环,依次类推。代码如下:

public static int[] twoSum(int[] nums,int target)
	{
		int[] result = new int[2];
		int[] list = new int[nums.length];
		for(int l = 0; l < nums.length; l++)
			list[l] = nums[l];
		Arrays.sort(nums);     //从小到大排序
		int j = nums.length - 1;
		int i = 0;
		while(i < j)
		{
			if(nums[i] + nums[j] == target)
			{
				//result[0] = i + 1;
				//result[1] = j + 1;
				break;
			}
			else if(nums[i] + nums[j] > target)
			{
				j--;
			}
			else if(nums[i] + nums[j] < target)
				i++;
		}
		int count = 0;
		for(int k = 0; k < list.length; k++)
		{
			
			//System.out.print(list[k] + "    ");
			if(list[k] == nums[i] || list[k] == nums[j])
			{
				result[count] = k + 1;
				count++;
			}	
			if(count == 2)
				break;
		}
		if(result[0] > result[1])
		{
			int tmp = result[0];
			result[0] = result[1];
			result[1] = tmp;
		}
		return result;
	}
上面的result数组只有两个值,因为题目中已经说了,确保数组中只有两个数字符合要求。

下面是threeSum的题

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.

    For example, given array S = {-1 0 1 2 -1 -4},

    A solution set is:
    (-1, 0, 1)
    (-1, -1, 2)

题意:还是给定一个数组,然后现在的target为0,求任意的三个数字的和为0,那么将所有可能都三个数的组合放到一个list中,并且要求在每个list中的数都是按照从小到大排列的。

题解:

此题我想到的方法是先排序,然后固定一个数,在剩下的数中,采用twoSum的方法来做,一个头和一个尾,不停的向下循环;当然得注意的是,因为如果碰到在循环中twoSum的时候,出现头和尾的下一个元素是重复的,那么下标就要往下走。具体的代码如下:

public List<List<Integer>> threeSum(int[] nums)
	{
		List<List<Integer>> result = new ArrayList<>();
		if(nums == null || nums.length < 3)
			return result;
		Arrays.sort(nums);
		int length = nums.length;
		for(int i = 0; i < length; i++)
		{
			if(i > 0 && nums[i] == nums[i - 1])
				continue;
			int target = 0 - nums[i];             //先固定一个数
			int j = i + 1,k = length - 1;
			while(j < k)      //套用twoSum的思想
			{
				if(nums[j] + nums[k] == target)
				{
					result.add(Arrays.asList(nums[i],nums[j],nums[k]));
					while(j < k && nums[j] == nums[j + 1])    //去除重复的
						j++;
					while(j < k && nums[k] == nums[k - 1])
						k--;
					j++;
					k--;
				}
				else if(nums[j] + nums[k] < target)
				{
					j++;
				}
				else 
					k--;
			}
		}
		return result;
	}

这是典型的将问题转化为twoSum的方法来做,可以AC的。可以学习这种方法。

最后一道题是fourSum的题:

Given an array S of n integers, are there elements abc, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
  • The solution set must not contain duplicate quadruplets.

    For example, given array S = {1 0 -1 0 -2 2}, and target = 0.

    A solution set is:
    (-1,  0, 0, 1)
    (-2, -1, 1, 2)
    (-2,  0, 0, 2)
题解:

此题可以采用twoSum的方法,也就是可以将4个数字分成两组,分别是2、2。然后就是采用twoSum的方法来做。

public List<List<Integer>> fourSum(int[] nums,int target)
	{
		Arrays.sort(nums);
		return nSum(nums,4,0,target);
	}
	public List<List<Integer>> nSum(int[] nums,int n,int idx,int target)
	{
		if(n == 2)
			return twoSum(nums,idx,target);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		for(int i = idx; i <= nums.length; i++)
		{
			List<List<Integer>> temp = nSum(nums,n - 1,i + 1,target - nums[i]);
			for(List<Integer> l : temp)
			{
				l.add(0,nums[i]);
			}	
			result.addAll(temp);
			int t = nums[i];
			while(i <= nums.length -  n && nums[i] == t)
			{
				i++;
			}
			i--;
		}
		return result;
	}
	public List<List<Integer>> twoSum(int[] nums,int idx,int target)
	{
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		int ptr1 = idx,ptr2 = nums.length - 1;
		while(ptr1 < ptr2)
		{
			if(nums[ptr1] + nums[ptr2] == target)
			{
				List<Integer> temp = new ArrayList<Integer>();
				temp.add(nums[ptr1]);
				temp.add(nums[ptr2]);
				result.add(temp);
				int t1 = nums[ptr1];
				int t2 = nums[ptr2];
				while(ptr1 < ptr2 && nums[ptr1] == t1)
				{
		     		ptr1++;
				}
				while(ptr1 < ptr2 && nums[ptr2] == t2)
				{
					ptr2--;
				}
			}
			else if(nums[ptr1] + nums[ptr2] < target)
				ptr1++;
			else 
				ptr2--;
		}
		return result;
	}

可以好好理解下,尤其是2Sum和ThreeSum,对后面的fourSum会有帮助。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值