题库
1 两数之和
15 三数之和
16 最接近的三数之和
18 四数之和
167两数之和-输入有序数组
170 两数之和-数据结构设计
259 较小的三数之和
371 两整数之和
633 平方数之和
653两数之和-输入BST
923三数之和的多种可能
1022 从根到叶的二进制数之和
1099 小于K的两数之和
模板
哈希map
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> hash = new HashMap<>();
for(int i = 0; i < nums.length; i++){
if(hash.containsKey(target - nums[i])){
return new int[]{hash.get(target - nums[i]),i};
}
hash.put(nums[i],i);
}
return new int[] {-1,-1};
}
}
二分
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new LinkedList<>();
// sort
Arrays.sort(nums);
// 3 foreach
int n = nums.length;
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
int t = -nums[i];
int j = i + 1, k = n - 1;
while (j < k) {
if (nums[j] + nums[k] > t) {
k--;
} else if (nums[j] + nums[k] < t) {
j++;
} else {
// find
List<Integer> ans = new LinkedList<>();
ans.add(nums[i]);
ans.add(nums[j]);
ans.add(nums[k]);
result.add(ans);
// 去除临近相同的元素
while (j < k && nums[j] == nums[j + 1]) j++;
while (j < k && nums[k] == nums[k - 1]) k--;
j++;
k--;
}
}
}
return result;
}
}
Nsums模板
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
return nSumTarget(nums, 4, 0, target);
}
public List<List<Integer>> nSumTarget(int[] nums, int n, int start, int target){
int sz = nums.length;
List<List<Integer>> res = new ArrayList<>();
if(n < 2 || sz < n){
return res;
}
if(n == 2){
int lo = start, hi = sz - 1;
while(lo < hi){
int sum = nums[lo] + nums[hi];
int left = nums[lo], right = nums[hi];
if(sum < target){
lo++;
}else if(sum > target){
hi--;
}else{
List<Integer> ans = new ArrayList<>();
ans.add(left);
ans.add(right);
res.add(ans);
while(lo < hi && nums[lo] == left) lo++;
while(lo < hi && nums[hi] == right) hi--;
}
}
}else{
for(int i = start; i < sz; i++){
List<List<Integer>> sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
for(List<Integer> arr : sub){
arr.add(nums[i]);
res.add(arr);
}
while(i < sz - 1 && nums[i] == nums[i + 1]) i++;
}
}
return res;
}
}
树
class Solution {
public int sumRootToLeaf(TreeNode root) {
return dfs(root, 0);
}
private int dfs(TreeNode root, int sum){
if(root == null) return 0;
sum = 2 * sum + root.val;
if(root.left == null && root.right == null){
return sum;
}
return dfs(root.left, sum) + dfs(root.right, sum);
}
}
题目
1 两数之和
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> hash = new HashMap<>();
for(int i = 0; i < nums.length; i++){
if(hash.containsKey(target - nums[i])){
return new int[]{hash.get(target - nums[i]),i};
}
hash.put(nums[i],i);
}
return new int[] {-1,-1};
}
}
15 三数之和
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int target = 0;
int n = nums.length;
for(int i = 0; i < n; i++){
List<List<Integer>> tuples = twoSumtarget(nums, i + 1, target - nums[i]);
for(List<Integer> tuple : tuples){
tuple.add(nums[i]);
res.add(tuple);
}
while(i < n - 1 && nums[i] == nums[i + 1]){
i++;
}
}
return res;
}
public List<List<Integer>> twoSumtarget(int[] nums, int start, int target){
int lo = start, hi = nums.length - 1;
List<List<Integer>> res = new ArrayList<>();
while(lo < hi){
int sum = nums[lo] + nums[hi];
int left = nums[lo], right = nums[hi];
if(sum < target){
lo++;
}else if(sum > target){
hi--;
}else{
List<Integer> ans = new ArrayList<>();
ans.add(left);
ans.add(right);
res.add(ans);
while(lo < hi && nums[lo] == left) lo++;
while(lo < hi && nums[hi] == right) hi--;
}
}
return res;
}
}
//时间复杂度O(n2)
// class Solution {
// public List<List<Integer>> threeSum(int[] nums) {
// List<List<Integer>> result = new LinkedList<>();
// // sort
// Arrays.sort(nums);
// // 3 foreach
// int n = nums.length;
// for (int i = 0; i < n; i++) {
// if (i > 0 && nums[i] == nums[i - 1]) continue;
// int t = -nums[i];
// int j = i + 1, k = n - 1;
// while (j < k) {
// if (nums[j] + nums[k] > t) {
// k--;
// } else if (nums[j] + nums[k] < t) {
// j++;
// } else {
// // find
// List<Integer> ans = new LinkedList<>();
// ans.add(nums[i]);
// ans.add(nums[j]);
// ans.add(nums[k]);
// result.add(ans);
// // 去除临近相同的元素
// while (j < k && nums[j] == nums[j + 1]) j++;
// while (j < k && nums[k] == nums[k - 1]) k--;
// j++;
// k--;
// }
// }
// }
// return result;
// }
// }
16 最接近的三数之和
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
class Solution {
public int threeSumClosest(int[] nums, int target) {
// 排序
Arrays.sort(nums);
int closestNum = nums[0] + nums[1] + nums[2];
for (int i = 0; i < nums.length - 2; i++) {
int l = i + 1, r = nums.length - 1;
while (l < r){
int threeSum = nums[l] + nums[r] + nums[i];
if (Math.abs(threeSum - target) < Math.abs(closestNum - target)) {
closestNum = threeSum;
}
if (threeSum > target) {
r--;
} else if (threeSum < target) {
l++;
} else {
// 如果已经等于target的话, 肯定是最接近的
return target;
}
}
}
return closestNum;
}
}
18 四数之和
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
return nSumTarget(nums, 4, 0, target);
}
public List<List<Integer>> nSumTarget(int[] nums, int n, int start, int target){
int sz = nums.length;
List<List<Integer>> res = new ArrayList<>();
if(n < 2 || sz < n){
return res;
}
if(n == 2){
int lo = start, hi = sz - 1;
while(lo < hi){
int sum = nums[lo] + nums[hi];
int left = nums[lo], right = nums[hi];
if(sum < target){
lo++;
}else if(sum > target){
hi--;
}else{
List<Integer> ans = new ArrayList<>();
ans.add(left);
ans.add(right);
res.add(ans);
while(lo < hi && nums[lo] == left) lo++;
while(lo < hi && nums[hi] == right) hi--;
}
}
}else{
for(int i = start; i < sz; i++){
List<List<Integer>> sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
for(List<Integer> arr : sub){
arr.add(nums[i]);
res.add(arr);
}
while(i < sz - 1 && nums[i] == nums[i + 1]) i++;
}
}
return res;
}
}
// public List<List<Integer>> fourSum(int[] nums, int target) {
// //排序+双指针
// Arrays.sort(nums);
// List<List<Integer>> res = new ArrayList<>();
// if(nums==null || nums.length<=3){
// return res;
// }
// int len = nums.length;
// for(int i = 0;i<len;i++){
// if(i-1>=0 && nums[i]==nums[i-1]){
// continue;
// }
// for(int j=i+1;j<len;j++){
// if(j-1>=i+1 && nums[j-1]==nums[j]){
// continue;
// }
// int tr = target - nums[i] - nums[j];
// int left = j+1,right = len-1;
// while(left<right){
// if(nums[left]+nums[right]==tr){
// List<Integer> tp = new ArrayList<>();
// tp.add(nums[i]);
// tp.add(nums[j]);
// tp.add(nums[left]);
// tp.add(nums[right]);
// res.add(tp);
// while(left<right && nums[left]==nums[++left]);
// while(left<right && nums[right]==nums[--right]);
// }else if(nums[left]+nums[right]>tr){
// right--;
// }else{
// left++;
// }
// }
// }
// }
// return res;
// }
167两数之和-输入有序数组
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
class Solution {
public int[] twoSum(int[] numbers, int target) {
if(numbers == null) return null;
int i = 0, j = numbers.length - 1;
while(i < j){
int sum = numbers[i] + numbers[j];
if(sum == target){
return new int []{i+1,j+1};
}else if(sum < target){
i++;
}else{
j--;
}
}
return new int[]{-1,-1};
}
}
170 两数之和-数据结构设计
输入:
["TwoSum", "add", "add", "add", "find", "find"]
[[], [1], [3], [5], [4], [7]]
输出:
[null, null, null, null, true, false]
解释:
TwoSum twoSum = new TwoSum();
twoSum.add(1); // [] --> [1]
twoSum.add(3); // [1] --> [1,3]
twoSum.add(5); // [1,3] --> [1,3,5]
twoSum.find(4); // 1 + 3 = 4,返回 true
twoSum.find(7); // 没有两个整数加起来等于 7 ,返回 false
import java.util.Collections;
class TwoSum {
private ArrayList<Integer> nums;
private Map<Integer, Integer> freq= new HashMap<>();
/** Initialize your data structure here. */
public TwoSum() {
this.nums = new ArrayList<Integer>();
}
/** Add the number to an internal data structure.. */
public void add(int number) {
freq.put(number, freq.getOrDefault(number, 0) + 1);
}
/** Find if there exists any pair of numbers which sum is equal to the value. */
public boolean find(int value) {
for(Integer key : freq.keySet()){
int other = value - key;
if(other == key && freq.get(key) > 1){
return true;
}
if(other != key && freq.containsKey(other)){
return true;
}
}
return false;
}
}
/**
* Your TwoSum object will be instantiated and called as such:
* TwoSum obj = new TwoSum();
* obj.add(number);
* boolean param_2 = obj.find(value);
*/
259 较小的三数之和
输入: nums = [-2,0,1,3], target = 2
输出: 2
解释: 因为一共有两个三元组满足累加和小于 2:
[-2,0,1]
[-2,0,3]
class Solution {
public int threeSumSmaller(int[] nums, int target) {
// 排序
Arrays.sort(nums);
int c = 0;
for (int i = 0; i < nums.length - 2; i++) {
int l = i + 1, r = nums.length - 1;
while (l < r){
int threeSum = nums[l] + nums[r] + nums[i];
if (threeSum >= target) {
r--;
} else if (threeSum < target) {
c += r - l;
l++;
}
}
}
return c;
}
}
371 两整数之和
不使用运算符 + 和 - ,计算两整数a 、b 之和。
示例 1:
输入: a = 1, b = 2
输出: 3
class Solution {
public int getSum(int a, int b) {
return b == 0 ? a : getSum((a ^ b), (a & b) << 1);
}
}
633 平方数之和
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。
输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
class Solution {
public boolean judgeSquareSum(int target) {
if(target < 0) return false;
int i = 0,j = (int) Math.sqrt(target);
while(i <= j){
int powSum = i * i + j * j;
if(powSum == target){
return true;
}else if(powSum > target){
j--;
}else{
i++;
}
}
return false;
}
}
653两数之和-输入BST
输入:
5
/ \
3 6
/ \ \
2 4 7
Target = 9
输出: True
public class Solution {
public boolean findTarget(TreeNode root, int k) {
List < Integer > list = new ArrayList();
inorder(root, list);
int l = 0, r = list.size() - 1;
while (l < r) {
int sum = list.get(l) + list.get(r);
if (sum == k)
return true;
if (sum < k)
l++;
else
r--;
}
return false;
}
public void inorder(TreeNode root, List < Integer > list) {
if (root == null)
return;
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
}
923三数之和的多种可能
输入:A = [1,1,2,2,3,3,4,4,5,5], target = 8
输出:20
解释:
按值枚举(A[i],A[j],A[k]):
(1, 2, 5) 出现 8 次;
(1, 3, 4) 出现 8 次;
(2, 2, 4) 出现 2 次;
(2, 3, 3) 出现 2 次。
class Solution {
public int threeSumMulti(int[] A, int target) {
int ret = 0, N = A.length;
int mod=1000000007;
Arrays.sort(A);
for (int i = 0; i < N - 2; i++) {
if (A[i] + A[i + 1] + A[i + 2] > target || A[i] + A[N - 2] + A[N - 1] < target) continue; // 减枝
int l = i + 1, r = N - 1;
while (l < r) {
int sum = A[i] + A[l] + A[r];
if (sum < target) l++;
else if (sum > target) r--;
else {
if (A[l] == A[r]) { // 如果后两个数相同,则组合数为 C(len, 2)
int len = r - l + 1;
ret = (ret + len * (len - 1) / 2) % mod;
break;
}
// 如果后两个数不同,且各自个数分为为lcnt, rcnt,则组合数为lcnt * rcnt
int lcnt = 1, rcnt = 1;
while (l + 1 < r && A[l + 1] == A[l])
{
l++; lcnt++;
}
while (r - 1 > l && A[r - 1] == A[r]){
r--; rcnt++;
}
l++; r--;
ret = (ret + lcnt * rcnt) % mod;
}
}
}
return ret;
}
}
1022 从根到叶的二进制数之和
输入:root = [1,0,1,0,1,0,1]
输出:22
解释:(100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22
class Solution {
public int sumRootToLeaf(TreeNode root) {
return dfs(root, 0);
}
private int dfs(TreeNode root, int sum){
if(root == null) return 0;
sum = 2 * sum + root.val;
if(root.left == null && root.right == null){
return sum;
}
return dfs(root.left, sum) + dfs(root.right, sum);
}
}
1099 小于K的两数之和
输入:nums = [34,23,1,24,75,33,54,8], k = 60
输出:58
解释:
34 和 24 相加得到 58,58 小于 60,满足题意。
class Solution {
public int twoSumLessThanK(int[] A, int k) {
Arrays.sort(A);
int l = 0, r = A.length - 1;
int result = Integer.MIN_VALUE;
while (l < r) {
if (A[l] + A[r] >= k) {
r--;
} else {
result = Math.max(result, A[l] + A[r]);
l++;
}
}
return result == Integer.MIN_VALUE ? -1 : result;
}
}