[LeetCode] 25倍速度被完虐的 Sum3
来源:互联网 发布:夏洛克妹妹欧洛丝 知乎 编辑:程序博客网 时间:2024/05/02 04:54
渣用了两个hash,结果速度是神的25倍
渣代码,hash存第三个数字附带统计出现次数,hash结果去重复,附带练了一下qsort所以98行
int[] n; public int partition(int start,int end){ int x=end; int i=start-1; int tmp; for(int j=start;j<end;j++){ if(n[j]<=n[x]){ i++; tmp=n[i]; n[i]=n[j]; n[j]=tmp; } } i++; tmp=n[x]; n[x]=n[i]; n[i]=tmp; return i; } public void qsort(int start, int end){ if(start > end) return; int i=partition(start,end); qsort(start,i-1); qsort(i+1,end); } HashSet<String> results=new HashSet<String>(); HashMap<Integer,Integer> nmap=new HashMap<Integer,Integer>(); public void addRes(int i, int j){ int l=0-i-j; if(l<=i){ int tmp=l; l=j; j=i; i=tmp; } if(i<l&&l<=j){ int tmp=j; j=l; l=tmp; } if(i==j&&j==l){ Integer m=nmap.get(i); if(m<3) return; } if(i==j||j==l){ Integer m=nmap.get(j); if(m<2) return; } String s=""+i+","+j+","+l; results.add(s); } public void genRes(ArrayList<ArrayList<Integer>> res){ Iterator<String> it=results.iterator(); while(it.hasNext()){ ArrayList<Integer> list=new ArrayList<Integer>(); String[] ss=it.next().split(","); for(String ts:ss) list.add(Integer.parseInt(ts)); res.add(list); } } public ArrayList<ArrayList<Integer>> threeSum(int[] num) { n=num; qsort(0,n.length-1); for(int i=0;i<n.length;i++){ Integer m=nmap.get(n[i]); if(m==null) m=1; else m++; nmap.put(n[i], m); } for(int i=0;i<n.length;i++) for(int j=i;j<n.length;j++){ int v=0-n[i]-n[j]; if(nmap.containsKey(v)){ // System.out.println("n[i]="+n[i]+" n[j]="+n[j]); addRes(n[i],n[j]); } } ArrayList<ArrayList<Integer>> reslist=new ArrayList<ArrayList<Integer>>(); genRes(reslist); return reslist; }
先看我仿照神代码写的再解释
public class Solution { int[] n;public int partition(int start, int end) {int x = end;int i = start - 1;int tmp;for (int j = start; j < end; j++) {if (n[j] <= n[x]) {i++;tmp = n[i];n[i] = n[j];n[j] = tmp;}}i++;tmp = n[x];n[x] = n[i];n[i] = tmp;return i;}public void qsort(int start, int end) {if (start > end)return;int i = partition(start, end);qsort(start, i - 1);qsort(i + 1, end);}ArrayList<ArrayList<Integer>> reslist = new ArrayList<ArrayList<Integer>>();public ArrayList<ArrayList<Integer>> threeSum(int[] num) {n = num;qsort(0, n.length - 1);Integer li=null;for (int i = 0; i < n.length; i++) {if(li!=null&&li==n[i])continue;li=n[i];int target = -n[i];int start = i + 1;int end = n.length - 1;while (start < end) {//find target from current start,endwhile (n[start] + n[end] != target&&start<end) {if (n[start] + n[end] < target)start++;elseend--;}//System.out.println("i= "+i+" start="+start+" end="+end);// equals to target once but maybe moreif(start>=end)break;addRes(n[i], n[start], n[end]);//remove the replicated datawhile(start<end&&start<n.length-1&&n[start]==n[start+1])start++;start++;while(start<end&&end>1&&n[end]==n[end-1])end--;end--;}}return reslist;}private void addRes(int i, int j, int k) {ArrayList<Integer> list = new ArrayList<Integer>();list.add(i);list.add(j);list.add(k);reslist.add(list);}}
这道题据说很常考,我觉得主要是它的优化空间真的很大。
最笨解显然是O(N3),主要问题有两个,肯定是先排序 没得说
1. 去重复问题,这个问题实在太蛋疼了,我的耗时主要就在这里
2. 双指针到底怎么用
分析一下神接法,先说双指针问题。我一开始想第一个外圈i肯定是从0到len,里面两个指针只用从i+1 len 就可以了。到这里还是没有错的,下一步,两个指针怎么走?
二分? 你输了。我也觉得是二分,也就是两个指针中,一个从i+1 到len遍历,一个飞着找对应解,算算复杂度,外圈n 第二圈也是n 里面是logn,所以复杂度是O(N2lgN),完蛋了。
其实是可以两个指针一步一步走的,我一开始也以为这样会丢解,后来自己推了一下,能证明这样是不会丢解的。假设遍历队列是 a1 a2 a3... an 从小到大排序好的,假设两个指针分别指在start 和 end的位置上,目标是target
如下遍历即可:
if start+end<target,start++;
if start+end >target, end--; 且这样不会丢解
证明:丢解的原因无非是在左边指针为start值时,end跳过了某个值。反之亦可,所以只看一组
当<target,对于这个end值,start之前的值一定无法匹配,因为是排序好的,之前的值加上end一定更小于target。所以只能尝试下一个start 如果这时候start++了,且start+end>target了,则新start之后的值一定也无法符合=target,因为都大,即这个end无解。这个end就可以跳过了。
所以双指针最后就是只是加起来遍历了i+1~len一遍.
再看重复问题。神处理的依然很绝。
我只想到了hash判重复,但其实可以在双指针里跳过重复,太绝了。
rewrite:
ArrayList<ArrayList<Integer>> reslist=new ArrayList<ArrayList<Integer>>(); int r1=Integer.MAX_VALUE; int r2=Integer.MAX_VALUE; public ArrayList<ArrayList<Integer>> threeSum(int[] num) { Arrays.sort(num); for(int i=0;i<num.length;i++){ if(i>0&&num[i]==num[i-1]) continue; int head=i+1; int tail=num.length-1; while(true){ if(head>=tail) break; int v=num[i]+num[head]+num[tail]; if(v==0){ genRes(num[i],num[head],num[tail]); head++; }else{ if(v<0){ head++; }else tail--; } } } return reslist; }private void genRes(int i, int j, int k) { if(r1==j&&r2==k) return; r1=j; r2=k; ArrayList<Integer> list=new ArrayList<Integer>(); list.add(i); list.add(j); list.add(k); reslist.add(list);}
- [LeetCode] 25倍速度被完虐的 Sum3
- 【数据结构与算法】【leetcode】sum2 sum3 sum4 Combination Sum
- 使Firefox速度提升4倍的密技
- 让程序的运行速度提高100倍
- 如果让你的insert操作速度增加1000倍
- IE9发布初期普及速度是IE8的5倍
- MongoDB Map Reduce速度提升20倍的优化宝典
- MongoDB MapReduce速度提升20倍的优化宝典
- MongoDB MapReduce速度提升20倍的优化宝典
- MongoDB MapReduce速度提升20倍的优化宝典
- 10倍以上提高Pentaho Kettle的MySQL写入速度
- MongoDB MapReduce速度提升20倍的优化宝典
- 10倍以上提高Pentaho Kettle的MySQL写入速度
- 两条速度相差1350倍的sql语句
- 如何将你的 MySQL 查询速度提升 300 倍
- 如何将你的 MySQL 查询速度提升 300 倍
- 如何将你的 MySQL 查询速度提升 300 倍
- 如何将你的 MySQL 查询速度提升 300 倍
- 最长公共子串(Longest-Common-Substring,LCS)
- VC C/C++ 4种方法获取文件大小 Windows API
- STL文件读写基础
- [leet code] Pascal's Triangle II
- 15分钟学会使用Git和远程代码库
- [LeetCode] 25倍速度被完虐的 Sum3
- 2013年伯乐在线最受欢迎的20篇技术博文
- 一行代码,浏览器变临时编辑器
- C语言:丹尼斯·里奇的不朽遗产
- 分布式系统的数据一致性
- AChartEngine应用之LineChart(模拟三角函数sin,cos)
- hdfs 数据一致性
- 什么是内存泄露
- 【经典例题】高次幂的后几位数