每日一题做题记录,参考官方和三叶的题解 |
- 题目要求
- 求凸包
- 思路一:Andrew算法
- Java
- C++
- 思路二:Graham算法
- Java
- C++
- 思路三:Jarvis算法
- Java
- C++
- 总结
明显是一道求凸包的题,虽然在今天之前完全不知道这是个啥……
思路一:Andrew算法 Javaclass Solution {
public int[][] outerTrees(int[][] trees) {
int n = trees.length;
if (n < 4) {
return trees;
}
/* 按照 x 大小进行排序,如果 x 相同,则按照 y 的大小进行排序 */
Arrays.sort(trees, (a, b) -> {
if (a[0] == b[0]) {
return a[1] - b[1];
}
return a[0] - b[0];
});
List<Integer> hull = new ArrayList<Integer>();
boolean[] used = new boolean[n];
/* hull[0] 需要入栈两次,不进行标记 */
hull.add(0);
/* 求出凸包的下半部分 */
for (int i = 1; i < n; i++) {
while (hull.size() > 1 && cross(trees[hull.get(hull.size() - 2)], trees[hull.get(hull.size() - 1)], trees[i]) < 0) {
used[hull.get(hull.size() - 1)] = false;
hull.remove(hull.size() - 1);
}
used[i] = true;
hull.add(i);
}
int m = hull.size();
/* 求出凸包的上半部分 */
for (int i = n - 2; i >= 0; i--) {
if (!used[i]) {
while (hull.size() > m && cross(trees[hull.get(hull.size() - 2)], trees[hull.get(hull.size() - 1)], trees[i]) < 0) {
used[hull.get(hull.size() - 1)] = false;
hull.remove(hull.size() - 1);
}
used[i] = true;
hull.add(i);
}
}
/* hull[0] 同时参与凸包的上半部分检测,因此需去掉重复的 hull[0] */
hull.remove(hull.size() - 1);
int size = hull.size();
int[][] res = new int[size][2];
for (int i = 0; i < size; i++) {
res[i] = trees[hull.get(i)];
}
return res;
}
public int cross(int[] p, int[] q, int[] r) {
return (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
}
}
- 时间复杂度: O ( n log n ) O(n \log n) O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n)
- 时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n)
class Solution {
public int[][] outerTrees(int[][] trees) {
int n = trees.length;
if (n < 4) {
return trees;
}
int bottom = 0;
/* 找到 y 最小的点 bottom*/
for (int i = 0; i < n; i++) {
if (trees[i][1] < trees[bottom][1]) {
bottom = i;
}
}
swap(trees, bottom, 0);
/* 以 bottom 原点,按照极坐标的角度大小进行排序 */
Arrays.sort(trees, 1, n, (a, b) -> {
int diff = cross(trees[0], a, b) - cross(trees[0], b, a);
if (diff == 0) {
return distance(trees[0], a) - distance(trees[0], b);
} else {
return -diff;
}
});
/* 对于凸包最后且在同一条直线的元素按照距离从小到大进行排序 */
int r = n - 1;
while (r >= 0 && cross(trees[0], trees[n - 1], trees[r]) == 0) {
r--;
}
for (int l = r + 1, h = n - 1; l < h; l++, h--) {
swap(trees, l, h);
}
Deque<Integer> stack = new ArrayDeque<Integer>();
stack.push(0);
stack.push(1);
for (int i = 2; i < n; i++) {
int top = stack.pop();
/* 如果当前元素与栈顶的两个元素构成的向量顺时针旋转,则d出栈顶元素 */
while (!stack.isEmpty() && cross(trees[stack.peek()], trees[top], trees[i]) < 0) {
top = stack.pop();
}
stack.push(top);
stack.push(i);
}
int size = stack.size();
int[][] res = new int[size][2];
for (int i = 0; i < size; i++) {
res[i] = trees[stack.pop()];
}
return res;
}
public int cross(int[] p, int[] q, int[] r) {
return (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
}
public int distance(int[] p, int[] q) {
return (p[0] - q[0]) * (p[0] - q[0]) + (p[1] - q[1]) * (p[1] - q[1]);
}
public void swap(int[][] trees, int i, int j) {
int temp0 = trees[i][0], temp1 = trees[i][1];
trees[i][0] = trees[j][0];
trees[i][1] = trees[j][1];
trees[j][0] = temp0;
trees[j][1] = temp1;
}
}
- 时间复杂度: O ( n log n ) O(n \log n) O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n)
- 时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n)
class Solution {
public int[][] outerTrees(int[][] trees) {
int n = trees.length;
if (n < 4) {
return trees;
}
int leftMost = 0;
for (int i = 0; i < n; i++) {
if (trees[i][0] < trees[leftMost][0]) {
leftMost = i;
}
}
List<int[]> res = new ArrayList<int[]>();
boolean[] visit = new boolean[n];
int p = leftMost;
do {
int q = (p + 1) % n;
for (int r = 0; r < n; r++) {
/* 如果 r 在 pq 的右侧,则 q = r */
if (cross(trees[p], trees[q], trees[r]) < 0) {
q = r;
}
}
/* 是否存在点 i, 使得 p 、q 、i 在同一条直线上 */
for (int i = 0; i < n; i++) {
if (visit[i] || i == p || i == q) {
continue;
}
if (cross(trees[p], trees[q], trees[i]) == 0) {
res.add(trees[i]);
visit[i] = true;
}
}
if (!visit[q]) {
res.add(trees[q]);
visit[q] = true;
}
p = q;
} while (p != leftMost);
return res.toArray(new int[][]{});
}
public int cross(int[] p, int[] q, int[] r) {
return (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
}
}
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( n ) O(n) O(n)
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( n ) O(n) O(n)
有亿点复杂,但能学个新算法,今天有点浪,明天搞完!
欢迎指正与讨论! |
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)