查看: 7706| 回复: 15
跳转到指定楼层
上一主题 下一主题
收起左侧

[数组] 3sum 不sort怎么做?

全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
我的代码如下但是对于1, 0, -1, 1 这个case res里面同时有 (1, 0, -1) 和 (0, -1, 1), 并没有做到去重,
而且还需要处理  0, 0,0 的case
有没有人有好的想法?
  1. class Solution {
  2.     public List<List<Integer>> threeSum(int[] nums) {
  3.         List<List<Integer>> res = new ArrayList<>();
  4.         Set<Integer> seen = new HashSet<>();
  5.         for(int i = 0; i <= nums.length - 3; i++){
  6.              if(seen.contains(nums[i])) continue;
  7.              int target = 0 - nums[i];
  8.              twosum(nums, i+1, nums.length - 1, target, nums[i], res);
  9.              seen.add(nums[i]);
  10.         }
  11.         
  12.         return res;
  13.     }
  14.    
  15.      public void twosum(int[] nums, int start, int end, int target, int first, List<List<Integer>> res){
  16.         Set<Integer> set = new HashSet<>();
  17.         for(int i = start; i <= end; i++){
  18.            int find = target - nums[i];
  19.            if(set.contains(find)){
  20.                  res.add(Arrays.asList(first, nums[i], find));
  21.            }
  22.           set.add(nums[i]);
  23.        }
  24.      }
  25. }
复制代码

评分

参与人数 1大米 +5 收起 理由
yumebou + 5

查看全部评分


上一篇:Facebook面筋问题!!!
下一篇:开个贴集中刷题
推荐
黓龙君 2017-11-7 08:35:44 | 只看该作者
全局:
为什么你不想sort? 不sort的话brute force,对每一个元素做 two sum就好了。
回复

使用道具 举报

推荐
thuxx 2018-11-12 14:02:01 | 只看该作者
全局:
  1. class Solution {
  2.     // 不用排序的版本,超时
  3.     public List<List<Integer>> threeSum(int[] nums) {
  4.         List<List<Integer>> results = new ArrayList<>();

  5.         Set<List<Integer>> set = new HashSet<>();
  6.         Map<Integer, Integer> map = new HashMap<>();
  7.         for (int num : nums) {
  8.             map.put(num, map.getOrDefault(num, 0) + 1);
  9.         }

  10.         for (int i = 0; i < nums.length; i++) {
  11.             // 注意 j 从 0 开始,因为内部还是需要判断升降序来去重,如果从 i + 1 开始可能会漏解
  12.             for (int j = 0; j < nums.length; j++) {
  13.                 int a = nums[i];
  14.                 int b = nums[j];
  15.                 int c = 0 - a - b;
  16.                 // 去重
  17.                 if (!(a >= b && b >= c)) {
  18.                     continue;
  19.                 }

  20.                 if (map.containsKey(c)) {
  21.                     map.put(a, map.get(a) - 1);
  22.                     map.put(b, map.get(b) - 1);
  23.                     map.put(c, map.get(c) - 1);
  24.                 } else {
  25.                     continue;
  26.                 }

  27.                 if (map.get(a) >= 0 && map.get(b) >= 0 && map.get(c) >= 0) {
  28.                     // 去重
  29.                     set.add(Arrays.asList(a, b, c));
  30.                 }

  31.                 map.put(a, map.get(a) + 1);
  32.                 map.put(b, map.get(b) + 1);
  33.                 map.put(c, map.get(c) + 1);
  34.             }
  35.         }

  36.         results.addAll(set);
  37.         return results;
  38.     }
  39. }
复制代码

  1. class Solution {
  2.     // 不用排序的版本,超时
  3.     public List<List<Integer>> threeSum(int[] nums) {
  4.         List<List<Integer>> results = new ArrayList<>();
  5.         Set<List<Integer>> set = new HashSet<>();

  6.         for (int i = 0; i < nums.length; i++) {
  7.             for (int j = 0; j < nums.length; j++) {
  8.                 int a = nums[i];
  9.                 int b = nums[j];
  10.                 int c = 0 - a - b;
  11.                 if (!(a >= b && b >= c)) {
  12.                     continue;
  13.                 }
  14.                 for (int k = 0; k < nums.length; k++) {
  15.                     if (nums[k] == c && i != j && j != k && i != k) {
  16.                         set.add(Arrays.asList(a, b, c));
  17.                     }
  18.                 }
  19.             }
  20.         }

  21.         results.addAll(set);
  22.         return results;
  23.     }
  24. }
复制代码


不排序两个版本均TLE, 前者过了倒数第二个case,最后一个3000个0的case 看脸跑,1200ms-1300ms之间,后者最后两个Case都TLE

评分

参与人数 4大米 +19 收起 理由
liqingfd + 1 很有用的信息!
qaert + 3 给你点个赞!
mierdalol + 10 给你点个赞!
liwenrui2008 + 5 给你点个赞!

查看全部评分

回复

使用道具 举报

推荐
jason123 2018-2-2 13:58:24 | 只看该作者
全局:
sizem 发表于 2018-2-2 13:38
求解 什麼是去重?

avoid duplicates in the result

评分

参与人数 1大米 +1 收起 理由
sizem + 1 很有用的信息!

查看全部评分

回复

使用道具 举报

🔗
mimesis 2017-11-7 05:21:21 | 只看该作者
全局:
我上礼拜想的时候是
2sum存hashmap的时候把两个值一起存起来,但是这样空间复杂度会高一些
不知道能不能更优
或者直接set存结果集?
回复

使用道具 举报

🔗
 楼主| slightlyOff 2017-11-7 06:24:00 | 只看该作者
全局:
mimesis 发表于 2017-11-7 05:21
我上礼拜想的时候是
2sum存hashmap的时候把两个值一起存起来,但是这样空间复杂度会高一些
不知道能不能 ...

对于1, 0, -1, 1这个case 你的解法是怎么work的呀
回复

使用道具 举报

🔗
mimesis 2017-11-7 09:22:20 | 只看该作者
全局:
slightlyOff 发表于 2017-11-7 06:24
对于1, 0, -1, 1这个case 你的解法是怎么work的呀

哦对。。我忘记了。。不能排序的话第一个外循环的数也没办法排重。。如果要排的话好像只能变成存3个数的hashmap那其实就是set去重结果集了
存3个数的时候比个大小从小到大存吧。。弱渣我想不到别的了orz
回复

使用道具 举报

🔗
bunnyNova 2017-12-21 11:04:39 | 只看该作者
全局:
mimesis 发表于 2017-11-7 09:22
哦对。。我忘记了。。不能排序的话第一个外循环的数也没办法排重。。如果要排的话好像只能变成存3个数的h ...

这个题我面试的时候被问到了,我说三个数从小到大排,然后存。面试官说我还是sort,不符合要求。于是这轮面试就挂了。
回复

使用道具 举报

🔗
magicsets 2017-12-21 13:07:07 | 只看该作者
全局:
不sort的话主要难点在于去除重复的答案,分两方面:

(1) Identity-去重
也就是说如果记录了一次(1, 0, -1)这样的结果,那么下一次出现(1, 0, -1)时,我们应该有一个数据结构可以判断这个结果是重复的

(2) Permutation-去重
也就是避免同时记录(1, 0, -1)和(-1, 1, 0)这样本质上相同的结果,去重方法是在枚举组合时,保持某种偏序关系——比如说三个数从小到大

我写了一份代码,可以用于提交LeetCode的3SUM:https://leetcode.com/problems/3sum/description/
不过这种不sort的代码速度挺慢的就是...

  1. #include <cstdint>
  2. #include <iostream>
  3. #include <unordered_map>
  4. #include <unordered_set>
  5. #include <vector>

  6. class Solution {
  7. public:
  8.   std::vector<std::vector<int>> threeSum(const std::vector<int> &nums) {
  9.     // 统计每个数字的个数
  10.     std::unordered_map<int, int> counts;
  11.     for (const int value : nums) {
  12.       ++counts[value];
  13.     }

  14.     std::vector<std::vector<int>> results;
  15.     std::unordered_set<std::uint64_t> existence;

  16.     for (const int l : nums) {
  17.       for (const int r : nums) {
  18.         // 设三个数为l, m, r
  19.         // 为了"Permutation-去重",只需要保留l <= m <= r的结果
  20.         const int m = -(l + r);
  21.         if (l > m || m > r) {
  22.           continue;
  23.         }

  24.         // 用于加速计算的pre-check: m存在
  25.         auto &mc = counts[m];
  26.         if (mc <= 0) {
  27.           continue;
  28.         }

  29.         // 拼接l, r以进行"Identity-去重"
  30.         // 这里为了方便用了uint64_t,也可以用std::pair<int, int>之类的,但需要写一个
  31.         // hash functor以提供给std::unordered_set,稍微麻烦一点
  32.         std::uint64_t code = (static_cast<std::uint64_t>(l) << 32) | r;
  33.         if (existence.find(code) != existence.end()) {
  34.           continue;
  35.         }

  36.         // l, m, r可能是两个或三个相同的数字,我们需要检查counts里对应的数字有那么多个
  37.         auto &lc = counts[l];
  38.         auto &rc = counts[r];
  39.         --lc; --mc; --rc;

  40.         if (lc >= 0 && mc >= 0 && rc >= 0) {
  41.           results.emplace_back(std::vector<int>({l, m, r}));
  42.           existence.emplace(code);
  43.         }

  44.         ++lc; ++mc; ++rc;
  45.       }
  46.     }

  47.     return results;
  48.   }
  49. };
复制代码
回复

使用道具 举报

🔗
stapollozxy 2017-12-21 14:22:23 | 只看该作者
全局:
时间n方 空间n吧?

评分

参与人数 1大米 +3 收起 理由
kagome + 3 给你点个赞!

查看全部评分

回复

使用道具 举报

🔗
jason123 2018-2-2 07:56:13 | 只看该作者
全局:
magicsets 发表于 2017-12-21 13:07
不sort的话主要难点在于去除重复的答案,分两方面:

(1) Identity-去重

其实你既然用hash table统计了,hash table的key就是所有的不同的num了,所以如果你的l , r 从hash table的key里来取值,你的O(n^2)就变成distinct的number的平方的,你的identity去重就可以不需要了
回复

使用道具 举报

🔗
sizem 2018-2-2 13:38:56 | 只看该作者
全局:
jason123 发表于 2018-2-2 07:56
其实你既然用hash table统计了,hash table的key就是所有的不同的num了,所以如果你的l , r 从hash table ...

求解 什麼是去重?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表