[leetcode]_K Sum 问题
问题:K Sum问题是一个问题系列,在一个数组中找K个数的和能够满足题目中要求。从2 Sum 到 3 Sum , 3 Sum Clozet , 4 Sum。。解法虽一开始不容易想到,但get到解题技能后,该系列的题目其实解法较为单一。
一、核心解题思路。Two Sum。
题目:一个数组a中,找寻两个数,使其和等于target。返回两个数的下标。
思路:最白目的思路是O(n2)解法,无需多言。精彩的解法能够O(n)完成算法。
将该数组进行排序。设置两个指针start,end指向数组的头尾。如果a[start] + a[end] < target,那么将start指针往后移,因为当前的和值比目标值小;反之,将end指针向前移,因为当前的和值比目标值大。直到两个指针相遇,结束查找。
代码:由于要返回两个数的下标,因此在对数组进行排序之前,需要记录数据的原始下标。
public class Solution {
public int[] twoSum(int[] numbers, int target) { if(numbers.length <= 1) return null; Pair[] pairs = new Pair[numbers.length];
for(int i = 0 ; i < numbers.length ; i++){
pairs[i] = new Pair(numbers[i] , i+1);
} Comparator<Pair> comparator = new Comparator<Pair>(){
public int compare(Pair o1 , Pair o2){
return o1.val > o2.val ? 1 : -1 ;
}
}; Arrays.sort(pairs , comparator); int index1 = 0 , index2 = numbers.length - 1; while(index1 < index2){
int temp = pairs[index1].val + pairs[index2].val;
if(temp == target) break;
else if(temp < target) index1++;
else index2--;
}
if(pairs[index1].index < pairs[index2].index) return new int[]{pairs[index1].index , pairs[index2].index};
else return new int[]{pairs[index2].index , pairs[index1].index};
}
} class Pair{
int val;
int index;
Pair(int x , int y){
val = x;
index = y;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
二、举一反三。3 Sum。
问题:一个数组a,判断其中是否存在三个数a , b , c 使其和为target。返回这些三元组集合。
思路:该问题可退化为 2 Sum问题来解答。先选择任意一个数a ,然后判断剩余数组中是否存在另外两个数的和等于target - a。<----这里就完全是2 Sum问题的方法了。
代码:
public ArrayList<ArrayList<Integer>> threeSum(int[] num) { ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); Arrays.sort(num); for(int i = 0 ; i < num.length ; i++){
int target = 0 - num[i];
//由于结果要求三元组的值要非递减顺序,因此将数组排序后,从头开始定第一个数据,后两个数据从该数据的后部选取。
for(int j = i + 1 , k = num.length - 1 ; j < num.length && k >= 0 && j < k ;){
int temp = num[j] + num[k];
if(temp == target){ boolean ifAdd = true; //judge duplicate
for(int index = 0 ; index < result.size() ; index++){
if(result.get(index).get(0) == num[i]
&& result.get(index).get(1) == num[j]
&& result.get(index).get(2) == num[k]){
ifAdd = false;
break;
}
}
if(ifAdd){
ArrayList<Integer> one = new ArrayList<Integer>();
one.add(num[i]);
one.add(num[j]);
one.add(num[k]);
result.add(one);
}
j++; }else if(temp < target) j++;
else k--;
}
}
return result;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
三、练习熟悉。3 Sum Closest。
题目:给顶一个数组a,求最接近target的三元组的和。输出该和。
思路:完全与3 Sum问题相同。唯一不同的地方在于,因为它是判断与target最接近,因此利用绝对值来判断当前和是否与target最接近。
代码:
public int threeSumClosest(int[] num, int target) { Arrays.sort(num);
int min = Integer.MAX_VALUE; for(int i = 0 ; i < num.length ; i++){ for(int j = i + 1 , k = num.length - 1 ; j < num.length && k >= 0 && j < k ;){
int threeSum = num[j] + num[k] + num[i];
if(threeSum == target) {
min = 0;
break;
}else{ int dis = target - threeSum;
//利用绝对值来判断是否与traget最接近。
if(Math.abs(dis) < Math.abs(min)) {
min = dis;
} if(dis > 0) j++;
else k--;
}
}
if(min == 0){
break;
}
}
return target - min;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
四、还是练习。4 Sum。
问题:一个数组a,寻找是否存在四个数a + b + c + d = target。返回四元组集合。
思路:先固定住一个数a , 然后寻找剩余数组中是否存在三个数和 等于 target - a(退化为3Sum),然后计算三个数和时,再先固定一个数b,然后寻找剩余数组中是否存在两个数和等于target-a -b(退化为2Sum)。
代码:
public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) { ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); if(num.length <= 3) return result; Arrays.sort(num); for(int i = 0 ; i <= num.length - 4 ; i++){
for(int j = i + 1 ; j <= num.length - 3 ; j++){
int start = j + 1;
int end = num.length - 1;
while(start < end){
int temp = num[i] + num[j] + num[start] + num[end];
if(temp == target){
boolean ifAdd = true;
for(int k = 0 ; k < result.size() ; k++){
if(result.get(k).get(0) == num[i] && result.get(k).get(1) == num[j]
&& result.get(k).get(2) == num[start] && result.get(k).get(3) == num[end]){
ifAdd = false;
break;
}
} if(ifAdd){
ArrayList<Integer> each = new ArrayList<Integer>();
each.add(num[i]);
each.add(num[j]);
each.add(num[start]);
each.add(num[end]);
result.add(each);
} start++; }else if(temp < target) start++;
else end--;
}
}
} return result;
}
因此,总结K Sum的问题,其核心思路就是2Sum问题,任何K > 2时,都可通过逐层退化,到2Sum。而2Sum问题,在将数据进行排序后,就可通过两个指针来达到要求。
[leetcode]_K Sum 问题的更多相关文章
- LeetCode:Path Sum I II
LeetCode:Path Sum Given a binary tree and a sum, determine if the tree has a root-to-leaf path such ...
- 剑指offer 65. 不用加减乘除做加法(Leetcode 371. Sum of Two Integers)
剑指offer 65. 不用加减乘除做加法(Leetcode 371. Sum of Two Integers) https://leetcode.com/problems/sum-of-two-in ...
- [LeetCode] Path Sum III 二叉树的路径和之三
You are given a binary tree in which each node contains an integer value. Find the number of paths t ...
- [LeetCode] Combination Sum IV 组合之和之四
Given an integer array with all positive numbers and no duplicates, find the number of possible comb ...
- [LeetCode] Max Sum of Rectangle No Larger Than K 最大矩阵和不超过K
Given a non-empty 2D matrix matrix and an integer k, find the max sum of a rectangle in the matrix s ...
- [LeetCode] Range Sum Query 2D - Mutable 二维区域和检索 - 可变
Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...
- [LeetCode] Range Sum Query - Mutable 区域和检索 - 可变
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...
- [LeetCode] Range Sum Query 2D - Immutable 二维区域和检索 - 不可变
Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...
- [LeetCode] Range Sum Query - Immutable 区域和检索 - 不可变
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...
随机推荐
- [POJ 2923] Relocation (动态规划 状态压缩)
题目链接:http://poj.org/problem?id=2923 题目的大概意思是,有两辆车a和b,a车的最大承重为A,b车的最大承重为B.有n个家具需要从一个地方搬运到另一个地方,两辆车同时开 ...
- ANR
/data/anr/traces.txt MySQL: select version();
- [转]sql利用游标循环,遍历表循环结果集
用 游标(Cursor) + While循环 的方法, 对Customers表中的CompanyName列进行遍历 ) declare pcurr cursor for select distinct ...
- android 开发进阶 自定义控件-仿ios自动清除控件
先上图: 开发中经常需要自定义view控件或者组合控件,某些控件可能需要一些额外的配置.比如自定义一个标题栏,你可能需要根据不同尺寸的手机定制不同长度的标题栏,或者更常见的你需要配置标题栏的背景,这时 ...
- cookie、session、sessionid 与jsessionid
可查看 http://www.cnblogs.com/fnng/archive/2012/08/14/2637279.html
- 【教程】【FLEX】#003 自定义事件、模块间通讯
本篇笔记,主要阐明 事件是如何创建 和 如何使用自定义事件达到模块之间通讯 的效果. 句子解释: 什么叫做模块之间的通讯呢?? 简单点说,就是两个模块之间可以互相传数据. A模块 可以接收到 B模块的 ...
- 仿qq空间相册的图片批量上传
效果: 转载请注明:http://www.cnblogs.com/TheViper/ 主要是flash组件的tilelist,这个很有用.还有对flash组件源码的一点修改hack. 还是代码很简单, ...
- js鼠标,键盘,坐标轴事件
鼠标按下事件,左键是0,滑轮是1,右键2 document.getElementById("box").onmousedown =function(e) { if (e.butto ...
- 洛谷P1467 循环数 Runaround Numbers
P1467 循环数 Runaround Numbers 89通过 233提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交 讨论 题解 最新讨论 暂时没有讨论 题目描述 循环数是 ...
- 互斥对象 Mutex 和MFC中的CMutex
互斥(Mutex)是一种用途非常广泛的内核对象.能够保证多个线程对同一共享资源的互斥访问.同临界区有些类似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共 ...