LeetCode(15) 3Sum
2017-11-22 18:32
351 查看
https://sodaoo.github.io/2017/11/21/LeetCode-14/
https://sodaoo.github.io
来我的网站查看更多 LeetCode 题解
Description :
An array S of n integers .are there elements a, b, c in S such that a+b+c=0 ?
Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[ [-1, 0, 1], [-1, -1, 2] ]
给你一个 int 类型的Array , 将所有相加等于0 的三个数找出来, 返回一个三元组的表 .
这个表一定不能重复 ,比如 : [-1,-1,2 ] 和 [-1,2,-1] 被认为是重复的 .
A solution set is:
[ [-1, 0, 1], [-1, -1, 2] ]
常规思路 :
– 将这个数组排序, 比如排序之后是 nums=(-99,-56,-34,-1,0,22,33,44,77)
– 写双重的 for 循环 ,判断 x = -(nums[i] , nums[j]) 是否在 nums[] 内
– 如果 x 在 nums[] 之内 : 说明找到了这样三个数 ,如果不在 就继续循环 .
这个代码写出来 , 用了三千个数据一跑 ,光荣的达到了两分钟之久, 我们
import time ;
t1 = time.time() ; t2 = time.time()
print(“t1 到 t2 耗时共计”,t2-t1,”秒.”) 发现 ,
查找的代码耗时 133s , 去重排了 3s 贼恐怖 .
科学计算
Python拥有一些内置的数据结构 ,比如str, int, list, tuple, dict等, collections模块在这些内置数据结构的基础上,提供了几个额外的数据结构:
– namedtuple(): 生成可以使用名字来访问元素内容的tuple子类
– deque: 双端队列,可以快速的从另外一侧追加和推出对象
– Counter: 计数器,主要用来计数
– OrderedDict: 有序字典
– defaultdict: 带有默认值的字典
忽然发现我们常用的 list , dict 处理大批数据的能力真的很慢 ,
(也许不是慢 ,是打开方式不对…)
有一个有100万元素的列表Lis ,欲将每个元素和其出现次数成对放入一个字典中 .常规做法:
但发现非常耗时,一秒钟只能遍历300多个元素。 这就非常蛋疼了 .此时我们可以引入一个collections库 ,
这个库里面有一个 计数器 Counter , 不知道采用了什么样的结构, 总之非常快
不到一秒钟就完成了上面的任务 ,代码 :
我们再来看一下计数器的特点 :
依据这一特点, 我们对我们耗时 3 分钟的代码做一下改进 :
改进之后, 查找的时间降低到了 4 s 去重的时间降低到了 0.003 s
虽然速度快了非常多, 但是还是超时 ,下面我们看一个 AC 的 702 ms 的代码:
C++ 解法 :
https://sodaoo.github.io
来我的网站查看更多 LeetCode 题解
Description :
An array S of n integers .are there elements a, b, c in S such that a+b+c=0 ?
Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[ [-1, 0, 1], [-1, -1, 2] ]
给你一个 int 类型的Array , 将所有相加等于0 的三个数找出来, 返回一个三元组的表 .
这个表一定不能重复 ,比如 : [-1,-1,2 ] 和 [-1,2,-1] 被认为是重复的 .
A solution set is:
[ [-1, 0, 1], [-1, -1, 2] ]
常规思路 :
– 将这个数组排序, 比如排序之后是 nums=(-99,-56,-34,-1,0,22,33,44,77)
– 写双重的 for 循环 ,判断 x = -(nums[i] , nums[j]) 是否在 nums[] 内
– 如果 x 在 nums[] 之内 : 说明找到了这样三个数 ,如果不在 就继续循环 .
for i in range(len(nums)): for j in range(i+1,len(nums)): if (0-nums[i]-nums[j]) in nums: a = list(); a.append(0-nums[i]-nums[j]);a.append(nums[i]);a.append(nums[j]) res.append(a) # 有可能有重复的三元组, 我们对每一个三元组排序,再去重就可以了 . # [-1,-1,2 ] 和 [-1,2,-1] 被认为是重复的.但是这两个被认为是不相等的 . # 所以我们排序, [-1,-1,2 ] 和 [-1,-1,2 ] 是相等的 .利用这一点去重 . # 去重代码 : for i in res: i.sort() # 对三元组排序 ress = list() for i in res: if i not in ress: ress.append(i)
这个代码写出来 , 用了三千个数据一跑 ,光荣的达到了两分钟之久, 我们
import time ;
t1 = time.time() ; t2 = time.time()
print(“t1 到 t2 耗时共计”,t2-t1,”秒.”) 发现 ,
查找的代码耗时 133s , 去重排了 3s 贼恐怖 .
科学计算
Python拥有一些内置的数据结构 ,比如str, int, list, tuple, dict等, collections模块在这些内置数据结构的基础上,提供了几个额外的数据结构:
– namedtuple(): 生成可以使用名字来访问元素内容的tuple子类
– deque: 双端队列,可以快速的从另外一侧追加和推出对象
– Counter: 计数器,主要用来计数
– OrderedDict: 有序字典
– defaultdict: 带有默认值的字典
忽然发现我们常用的 list , dict 处理大批数据的能力真的很慢 ,
(也许不是慢 ,是打开方式不对…)
有一个有100万元素的列表Lis ,欲将每个元素和其出现次数成对放入一个字典中 .常规做法:
dic = {} for i in Lis: dic[i] = Lis.count(i)
但发现非常耗时,一秒钟只能遍历300多个元素。 这就非常蛋疼了 .此时我们可以引入一个collections库 ,
这个库里面有一个 计数器 Counter , 不知道采用了什么样的结构, 总之非常快
不到一秒钟就完成了上面的任务 ,代码 :
import collections cou = collections.Counter(Lis) print(cou) #不到一秒钟就完成了
我们再来看一下计数器的特点 :
>>> a = [2,2,2,3,3,4] >>> cou = collections.Counter(a) >>> cou Counter({2: 3, 3: 2, 4: 1}) # 元素后面是出现的次数 >>> 4 in cou True >>> 1 in cou False >>> cou[3] 2 >>> cou[4] 1 >>> cou[2] 3 # cou 是表示 n 这个元素出现的次数, 如示 3 这个元素出现了3 次, 2 这个元素出现了 3 次.
依据这一特点, 我们对我们耗时 3 分钟的代码做一下改进 :
改进之后, 查找的时间降低到了 4 s 去重的时间降低到了 0.003 s
import collections class Solution: def threeSum(self, nums): counter = collections.Counter(nums) del nums ; nums = counter # nums现在是一个计数器 . res = list() for i in range(len(nums)): for j in range(i+1,len(nums)): # 下面都是一样的了........
虽然速度快了非常多, 但是还是超时 ,下面我们看一个 AC 的 702 ms 的代码:
from collections import Counter class Solution: def threeSum(self, nums): """ :type nums: List[int] :rtype: List[List[int]] """ counter = collections.Counter(nums) # 如果 0 出现的次数 > 3 ,就加入一个 [0,0,0] 的三元组 ans = [] if counter[0] < 3 else [[0, 0, 0]] # 负数由大到小, 如 (-2 到 -77777) ngs = sorted([x for x in counter if x<0], reverse=True) # 正数由小到大, 如 (2 到 88888 ) n_ngs = sorted([x for x in counter if x>=0]) # 正负排序之后 , 更利于查找 # 双重循环 for n_ng in n_ngs: for ng in ngs: need = -(ng + n_ng) # <-need是第三个数 if need in counter: # 根据大小决定在元组的顺序, 不用去重了 . if (need == ng or need == n_ng) and counter[need] > 1: ans.append([ng, need, n_ng]) elif need < ng: ans.append([need, ng, n_ng]) elif n_ng < need: ans.append([ng, n_ng, need]) return ans # (time :1522 ms ,beat 51.82%)
C++ 解法 :
vector<vector<int> > threeSum(vector<int> &num) { vector<vector<int> > res; std::sort(num.begin(), num.end()); for (int i = 0; i < num.size(); i++) { int target = -num[i]; int front = i + 1; int back = num.size() - 1; while (front < back) { int sum = num[front] + num[back]; // Finding answer which start from number num[i] if (sum < target) front++; else if (sum > target) back--; else { //find sum == target that is -num[i] . vector<int> triplet(3, 0); triplet[0] = num[i]; triplet[1] = num[front]; triplet[2] = num[back]; res.push_back(triplet); // Processing duplicates of Number 2 // Rolling the front pointer to the next different number forwards while (front < back && num[front] == triplet[1]) front++; // Processing duplicates of Number 3 // Rolling the back pointer to the next different number backwards while (front < back && num[back] == triplet[2]) back--; } } // Processing duplicates of Number 1 while (i + 1 < num.size() && num[i + 1] == num[i]) i++; } return res; } // (time :105ms ,beat 80.2% )
相关文章推荐
- Leetcode 15 3Sum
- LeetCode 15 3Sum
- [LeetCode] 15. 3Sum
- LeetCode(15)题解--3Sum
- [Leetcode] 15. 3Sum
- LeetCode-15-3Sum
- LeetCode15 3Sum
- [LeetCode]--15. 3Sum
- Leetcode Q15: 3Sum
- Leetcode 15 [medium]--3Sum
- leetcode-15-3sum
- LeetCodet题解--15. 3Sum
- LeetCode之15_3Sum
- leetcode 15 3sum
- leetcode15 3Sum
- Leetcode - 15. 3Sum
- leetcode 15 3sum问题
- leetcode: 15. 3Sum
- 015_LeetCode_15 3Sum 题解
- LeetCode_OJ【15】3Sum