[Google] Given an array of Integer, return all valid triangles 给一个int数组, 返回所有可能的三角形
这个题目好像有很多变种, 比如给一个int数组, 返回所有的不重复数字组成的三角形, 或者返回所有等腰/直角三角形. 反正就是多几个限制和少几个限制. 我遇到的这个是返回所有的可能的三角形, 这其中包含:等边,等腰等等, 只要是Valid就可以.
传统解法就是O(n^3)的暴力, 当然, 这肯定不是我们想要的. 就不多说了.
说到三角形,基本看懂中文的都知道两个特性:
- 两边之和大于第三边
- 两边之差小于第三边
对于一个已经排序的数组, 我们用第一条就可以了. 证明:
Assume,x,y,z are three int, 0<x<=y<=z, if z < x-y, then y+z < x (against to 1), so z < x-y false
最后, 我们还要去重, 因为数组会有{4,4,4}, 所以要把选出的三边排序一下, 然后用HashSet的原理去重.
public static HashSet<ArrayList<Integer>> findAllTriAngle(int[] A) { HashSet<ArrayList<Integer>> result = new HashSet<ArrayList<Integer>>(); Arrays.sort(A); for (int i = 0; i < A.length; ++i) { int k = i; for (int j = i; j < A.length; ++j) { while (k < A.length && A[i] + A[j] > A[k]) // 两边之和大于第三边, k是第三边, 找第三边的最大界限 // two edges's sum must be larger than third edge. k is the third one ++k; for (int l = j; l < k; l++) { ArrayList<Integer> tmp = new ArrayList<Integer>(); tmp.add(A[i]); tmp.add(A[j]); tmp.add(A[l]); Collections.sort(tmp); result.add(tmp); } } } return result; }
算法思路是:
- 双指针i和j, i扫全部, j从i开始往后扫
- 每次j扫的时候, 用k往前扫到可能的所有边.
- 然后sort一下这些边, 放进result里
这个是O(n^2)的算法, 在第二个for loop里, 虽然有一个while和一个for, 但是他们的开始点是k, 而k每次从i开始, 所以是O(n^2), 如果不理解,可以这样想, k虽然在j里面做循环, 但是开始时,j和k的值是一样的, 都是i, 所以虽然k是nest 循环, 但是和j是”平行”的.
Leave A Comment