• 【LeetCode】N数和


    1. 3Sum

    给定一个无序数组(可能存在重复元素),是否存在三个数之和为0,输出所有不重复的三元组

    e.g. 给定数组 [-1, 0, 1, 2, -1, -4],

    结果集为:
    [
      [-1, 0, 1],
      [-1, -1, 2]
    ]

    原理:

    首先升序排序

    ----------------------------------------------------
    ^  ^                                               ^
    |  |                                               |
    |  j                                               k
    i

    j 往后扫,k 往前扫

    三数和 < 0 就 j++,> 0 就 k--

    直到 == 0 再取下一组

    C++实现:

     1 vector<vector<int>> threeSum(vector<int>& nums) {
     2     vector<vector<int>> result;
     3     sort(nums.begin(), nums.end());
     4     for (int i = 0; i < nums.size(); i++) {
     5         // 控制i不重复,只指向一组重复数字的第一个
     6         if (i > 0 && nums[i] == nums[i-1])
     7             continue;
     8         int j = i + 1, k = nums.size() - 1;
     9         while (j < k) {
    10             if (nums[i] + nums[j] + nums[k] < 0) {
    11                 j++;
    12             } else if (nums[i] + nums[j] + nums[k] > 0) {
    13                 k--;
    14             } else {
    15                 result.push_back({nums[i], nums[j], nums[k]});
    16                 // 控制j不重复,只指向一组重复数字的第一个
    17                 while (j < k && nums[j] == nums[j+1])
    18                     j++;
    19                 // 控制k不重复,只指向一组重复数字的最后一个
    20                 while (j < k && nums[k] == nums[k-1])
    21                     k--;
    22                 j++;
    23                 k--;
    24             }
    25         }
    26     }
    27     return result;
    28 }    

    第4行如果写 i < nums.size() - 2会报 Runtime Error 错,不知道为什么?

    2. 3Sum Closest

    给定一个无序数组(可能存在重复元素),是否存在三个数之和最接近给定数target,输出这三个数的和。(假设每条输入只有唯一答案)

    e.g. 给定数组 [-1, 2, 1, -4],target = 1

    则最接近target的和为2 (-1 + 2 + 1 = 2)

    C++实现:

     1 int threeSumClosest(vector<int>& nums, int target) {
     2     // 数组元素小于等于3个则直接返回数组和
     3     if (nums.size() <= 3) {
     4         return accumulate(nums.begin(), nums.end(), 0);
     5     }
     6     int close = nums[0] + nums[1] + nums[2];
     7     sort(nums.begin(), nums.end());
     8     for (int i = 0; i < nums.size(); i++) {
     9         if (i > 0 && nums[i] == nums[i-1])
    10             continue;
    11         int j = i + 1, k = nums.size() - 1;
    12         while (j < k) {
    13             int current = nums[i] + nums[j] + nums[k];
    14             if (abs(current - target) < abs(close - target)) {
    15                 close = current;
    16                 if (current == target) {
    17                     return current;
    18                 }
    19             }
    20             (current < target) ? j++ : k--;
    21         }
    22     }
    23     return close;
    24 }

    PS:

    C++对应的Java代码

    vector<vector<int>>                                            List<List<Integer>>
    sort(nums.begin(), nums.end());                                Arrays.sort(nums);
    result.push_back({nums[i], nums[j], nums[k]});                 result.add(Arrays.asList(nums[i], nums[j], nums[k]));
    abs(n)                                                         Math.abs(n)

    3. 4Sum

    给定一个无序数组(可能存在重复元素),是否存在四个数之和为目标数target,输出所有不重复的四元组

    e.g. 给定数组[1, 0, -1, 0, -2, 2],target = 0.

    结果集为:
    [
      [-1, 0, 0, 1],
      [-2, -1, 1, 2],
      [-2, 0, 0, 2]
    ]

    原理与 3 Sum 相似,首先升序排序,i 从第一个扫到最后,j 从 i + 1 扫到最后。

    两个指针为 p 和 k ,p 往后扫,k 往前扫,四数和 < 0 就 p++,> 0 就 k--;直到 == 0 再取下一组 p 和 k。

    C++实现:

     1 vector<vector<int>> fourSum(vector<int>& nums, int target) {
     2     int n = nums.size();
     3     if (n < 4)    return {};
     4     vector<vector<int>> result;
     5     sort(nums.begin(), nums.end());
     6     for (int i = 0; i < n - 3; i++) {
     7         if (i > 0 && nums[i] == nums[i - 1])    continue;
     8         // 提高效率,本轮能取的最小的和与本轮能取的最大的和
     9         if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target)   break;
    10         if (nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target)   continue;
    11         for (int j = i + 1; j < n - 2; j++) {
    12             if (j > i + 1 && nums[j] == nums[j - 1])    continue;
    13             // 提高效率,本轮能取的最小的和与本轮能取的最大的和
    14             if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
    15             if (nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) continue;
    16             // 最后两个指针p和k在最内层while上面定义
    17             // 如模仿三数和在上面定义k并在j循环体内控制条件写j < k会导致j扫不到最后
    18             int p = j + 1, k = n - 1;
    19             while (p < k) {
    20                 if (nums[i] + nums[j] + nums[p] + nums[k] < target)  p++;
    21                 else if (nums[i] + nums[j] + nums[p] + nums[k] > target)  k--;
    22                 else {
    23                     result.push_back({nums[i], nums[j], nums[p], nums[k]});
    24                     while (p < k && nums[p] == nums[p + 1]) p++;
    25                     while (p < k && nums[k] == nums[k - 1]) k--;
    26                     p++;
    27                     k--;
    28                 }
    29             }
    30         }
    31     }
    32     return result;
    33 }
  • 相关阅读:
    初步掌握HDFS的架构及原理
    Hadoop 生态系统
    安装Hadoop,让word count飞起来
    十分钟看透MapReduce
    初识Hadoop
    线性回归-理论篇
    逻辑回归
    hdu 4848 Wow! Such Conquering! (floyd dfs)
    hdu 4856 Tunnels (记忆化搜索)
    poj 3237 Tree [LCA] (树链剖分)
  • 原文地址:https://www.cnblogs.com/wayne793377164/p/7008811.html
Copyright © 2020-2023  润新知