2sum问题
这道题在剑指 offer 上面有,具体的链接为https://www.nowcoder.com/practice/390da4f7a00f44bea7c2f3d19491311b?tpId=13&tqId=11195&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
不会太难,所以此处不再赘述3-sum问题
这道题在 Leetcode 上面有,链接为:https://leetcode.com/problems/3sum/description/
题目描述:
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
Example: Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is: [ [-1, 0, 1], [-1, -1, 2]]
解题思路:
1)先将数组排序
2)从最后一个数字开始,把他的指针设为i, j = 0, k = i -1;
然后若 j+k = -i,则表示找到了一个三元组
若 j + k < -i, 则 j 往右移动
若 j + k > -i, 则k往左移动
复杂度分析:由于 j 和 k 是相向运动的,所以第二层的循环会在n次之内结束,时间复杂度为O(n^2)
代码实现:
public static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> a = new ArrayList<List<Integer>>();
HashSet<String> hs = new HashSet<String>();
// 排序
Arrays.sort(nums);
// 排除异常情况
if ( nums == null || nums.length < 3 )
return a;
// 只要考虑所有非负数的情况就好了
for ( int i = nums.length - 1; nums[i] >= 0 && i >= 2; i-- ) {
int j = 0;
int k = i - 1;
while ( j < k && nums[k] >= -nums[i] && nums[j] <= nums[i] ) {
// 此处可以提前跳出循环
if ( nums[j] + nums[k] > -nums[i] ) {
k--;
}
else if ( nums[j] + nums[k] < -nums[i] ) {
j++;
}
else {
ArrayList<Integer> t = new ArrayList<Integer>();
t.add(nums[j]);
t.add(nums[k]);
t.add(nums[i]);
if ( !hs.contains(t.toString()) ) {
// 用集合来避免重复的三元组
a.add(t);
hs.add(t.toString());
}
j++;
k--;
}
}
if ( nums[i-1] == nums[i] ) { // 避免多个一样的i
i--;
}
}
return a;
}
- 4-sum问题
链接:https://leetcode.com/problems/4sum/description/
思路:
第一种想法是改造3-sum问题的解法,把外层遍历改成两层 i1 和 i2 ,然后内层是遍历[0, i2)找到所有的解,这样的算法时间复杂度是O(n^3)
第二种想法是O(n^2)的算法,借助了 HashMap 来实现
1)先将数组排序
2)枚举所有的(i,j)对的和sum( i < j),以 sum 为 key,(i,j) 为 value,放到 HashMap 中,此时 sum 的值会有重复的,所以 value 设计成 一个 ArrayList。这个步骤的时间复杂度是O(n^2)
3) 枚举所有的 (v1, v2)对,看 target - v1 - v2 是否在 HashMap 里面,此时要过滤
v1, v2 和 HashMap 里面的对重复的情况,这个步骤的时间复杂度是O(n^2)
代码实现
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
HashSet<String> hs = new HashSet<String>();
HashMap<Integer, ArrayList<Integer>> hm
= new HashMap<Integer, ArrayList<Integer>>();
// 排序
Arrays.sort(nums);
// 排除异常情况
if ( nums == null || nums.length < 4 )
return ans;
// 建立 Hash 表
for ( int i = 0; i < nums.length -1; i++ ) {
for ( int j = i+1; j < nums.length; j++ ) {
int sum = nums[i] + nums[j];
if ( hm.containsKey(sum) ) {
hm.get(sum).add(i);
hm.get(sum).add(j);
}
else {
ArrayList<Integer> a = new ArrayList<>();
a.add(i);
a.add(j);
hm.put(sum, a);
}
}
}
for ( int i = 0; i < nums.length -1; i++ ) {
for ( int j = i+1; j < nums.length; j++ ) {
if ( hm.containsKey(target - nums[i] - nums[j]) ) {
ArrayList<Integer> a = hm.get(target - nums[i] - nums[j]);
for ( int k = 0; k < a.size(); k += 2 ) {
if ( a.get(k) == i || a.get(k+1) == i
|| a.get(k) == j || a.get(k+1) == j ) {
continue;
}
else {
ArrayList<Integer> t = new ArrayList<Integer>();
t.add(nums[i]);
t.add(nums[j]);
t.add(nums[a.get(k)]);
t.add(nums[a.get(k+1)]);
Collections.sort(t, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return ( o1 > o2 )?1: -1;
}
});
if ( !hs.contains(t.toString()) ) { // 用集合来避免重复
ans.add(t);
hs.add(t.toString());
}
}
}
}
}
}
return ans;
}