Leetcode N数之和

这篇博客主要探讨了LeetCode中与数之和相关的题目,包括两数、三数、四数之和的多种解法,涉及哈希映射、二分查找等算法,并提到了针对有序数组和BST的特定解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题库

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;
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值