(一)Two Sum
https://leetcode.com/problems/two-sum/description/
题目:对一个无重复元素的无序数组,找到满足两个数和为target的组合并返回两数下标(该数组必定且只存在一个满足条件的组合,且一个元素不可使用两次);
解答:
法一:HashMap:将 nums[index] 和 index 作为key, value值存入hashmap,寻找是否存在key为(target - nums[i])的组合,若找到则返回结果;
第一次犯错:需要先寻找key为(target - nums[i])的组合,再讲当前index的信息存入map,以避免当前index使用两次!
代码:
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) {
res[0] = map.get(target - nums[i]);
res[1] = i;
break;
}
map.put(nums[i], i);
}
return res;
}
}
法二:Two Pointer :使用i,j两指针循环遍历找到目标值;
代码:
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] + nums[i] == target) {
res[0] = i;
res[1] = j;
break;
}
}
}
return res;
}
}
(二)Two Sum II - Input Array is Sorted
https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/
题目:同(一),但数组元素按升序排列;
解答:使用Two Pointer效率更高且节省空间;
代码:
class Solution {
public int[] twoSum(int[] numbers, int target) {
int left = 0;
int right = numbers.length - 1;
int[] res = new int[2];
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum > target) {
right--;
} else if (sum < target) {
left++;
} else {
res[0] = left + 1;
res[1] = right + 1;
break;
}
}
return res;
}
}
(三)Two SumIII - Data Structure Design
https://leetcode.com/problems/two-sum-iii-data-structure-design/description/
题目:同(一),但是要求在一个class按指定要求完成
解答:使用HashMap, 存储数值以及该数值出现次数,以避免同一元素使用两次的情况;
第一次犯错:使用HashSet, 没有考虑同一元素重复使用的情况;
代码:
class TwoSum {
Map<Integer, Integer> map;
/** Initialize your data structure here. */
public TwoSum() {
map = new HashMap<>();
}
/** Add the number to an internal data structure.. */
public void add(int number) {
if (map.containsKey(number)) {
map.put(number, map.get(number) + 1);
} else {
map.put(number, 1);
}
}
/** Find if there exists any pair of numbers which sum is equal to the value. */
public boolean find(int value) {
Iterator<Integer> it = map.keySet().iterator();
while (it.hasNext()) {
int temp = it.next();
if (map.containsKey(value - temp)) {
if (temp == value - temp && map.get(temp) < 2) {
continue;
} else {
return true;
}
}
}
return false;
}
}
(四)3Sum
https://leetcode.com/problems/3sum/description/
题目:求一个无序数组中所有和为0的3个数组合;
解答:将无序数组排列后,与(二)相似;
第一次犯错:没有考虑返回的array里有重复元素的情况,如[0,0,0,0]错误地返回了[[0,0,0],[0,0,0]]
代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int prev = 0;
for (int i = 0; i < nums.length; i++) {
if (i > 0 && nums[i] == prev) {
continue;
}
prev = nums[i];
int left = i + 1;
int right = nums.length - 1;
int prevL = 0;
int prevR = 0;
while (left < right) {
//avoid duplicate elements
if (right < nums.length - 1) {
while (right >= 0 && nums[right] == prevR) {
right --;
}
}
if (left > i + 1) {
while (left < nums.length && nums[left] == prevL) {
left++;
}
}
if (left < right) {
int sum = nums[left] + nums[right];
if (sum > - nums[i]) {
prevR = nums[right];
right--;
} else if (sum < -nums[i]) {
prevL = nums[left];
left++;
} else {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
res.add(list);
prevL = nums[left];
prevR = nums[right];
left++;
right--;
}
}
}
}
return res;
}
}
(五)3Sum Closest
https://leetcode.com/problems/3sum-closest/description/
题目:对于一个无序数组,返回3个数的和最接近于target的和值(假设有且只有一个解);
解答:在(四)基础上(可以不考虑元素重复的情况),实时存储当前最接近target的值即可;
代码:
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int abs = Integer.MAX_VALUE;
int res = 0;
for (int i = 0; i < nums.length; i++) {
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[left] + nums[right] + nums[i];
if (Math.abs(sum - target) < abs) {
res = sum;
abs = Math.abs(sum - target);
}
if (sum > target) {
right--;
} else if (sum < target) {
left++;
} else {
return target;
}
}
}
return res;
}
}
(六)4Sum
https://leetcode.com/problems/4sum/description/
题目:求一个无序数组中所有和为target的4个数组合,元素不可重复;
解答:在 3Sum 基础上增加一个循环;
代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int prev1 = 0;
for (int i = 0; i < nums.length; i++) {
if (i > 0 && nums[i] == prev1) {
continue;
}
prev1 = nums[i];
int prev2 = 0;
for (int j = i + 1; j < nums.length; j++) {
if (j > i + 1 && nums[j] == prev2) {
continue;
}
prev2 = nums[j];
int left = j + 1;
int right = nums.length - 1;
int prevL = 0;
int prevR = 0;
while (left < right) {
//avoid duplicate elements
if (right < nums.length - 1) {
while (right >= 0 && nums[right] == prevR) {
right --;
}
}
if (left > j + 1) {
while (left < nums.length && nums[left] == prevL) {
left++;
}
}
if (left < right) {
int sum = nums[left] + nums[right] + nums[i] + nums[j];
if (sum > target) {
prevR = nums[right];
right--;
} else if (sum < target) {
prevL = nums[left];
left++;
} else {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[left]);
list.add(nums[right]);
res.add(list);
prevL = nums[left];
prevR = nums[right];
left++;
right--;
}
}
}
}
}
return res;
}
}
(七)4Sum II
https://leetcode.com/problems/4sum-ii/description/
题目:4个数组中每个数组选一个数,要求返回4数和为0的组合个数;
解答:将两数和以及出现次数存在HashMap中,用另外两数和的反数来判断是否存在于HashMap中;该方法的时间和空间复杂度均为O(n*n);
代码:
public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
int res = 0;
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < A.length; i++) {
for (int j = 0; j < B.length; j++) {
int sum = A[i] + B[j];
if (map.containsKey(sum)) {
map.put(sum, map.get(sum) + 1);
} else {
map.put(sum, 1);
}
}
}
for (int i = 0; i < C.length; i++) {
for (int j = 0; j < D.length; j++) {
int sum = C[i] + D[j];
if (map.containsKey(-sum)) {
res += map.get(-sum);
}
}
}
return res;
}
}