• 算法导论第四版学习——习题三Collinear Points


    题目正文:

    http://coursera.cs.princeton.edu/algs4/assignments/collinear.html

    作业难点:

    1、仔细思考会感觉有很多实现方法,但是如果没有适当使用排序,算法时间复杂度就会轻易超过要求。(包括暴力算法)

    2、隐含需要实现自己的数据结构用来组织“线”的集合,当然也可以用Stack或者Queue或者LinkedList,但是我个人是自己实现的。

    3、由于一条线段只能出现一次,所以有一个去重的问题。(最难)

    作业技巧:

    1、基本按照题目的先后顺序实现,结合视频学习中的一些知识点就可以把任务串起来,不会无从下手。

    2、SlopTo的计算结果和点数组的排列顺序有关吗?A.SlopeTo(B)和B.SlopeTo(A)其实是一样的,合理利用cache防止多次计算。

    3、在暴力方法中,引入排序可以解决去重问题。

    4、如果去重是通过在结果集合中查找是否存在,就铁定会超过复杂度要求,所以必须在添加结果集之前就能判断。

    这里就有一个重要推论:a-b-c-d线段,无论从a开始查找还是从b开始查找,线段最大和最小点都不变为a和d,所以我们只需要找到起始点为线段最小点的线段就可以了,其他线段均抛弃即可

    代码参考:

    (这是我自己亲测100分的答案,不代表写得最好,请在自己实在完成不了的时候再看,不然的话做这个题目的意义一点都没有)

      1 import edu.princeton.cs.algs4.StdDraw;
      2 
      3 /******************************************************************************
      4  *  Compilation:  javac Point.java
      5  *  Execution:    java Point
      6  *  Dependencies: none
      7  *
      8  *  An immutable data type for points in the plane.
      9  *  For use on Coursera, Algorithms Part I programming assignment.
     10  *
     11  ******************************************************************************/
     12 import java.util.Comparator;
     13 
     14 
     15 public class Point implements Comparable<Point> {
     16     private final int x; // x-coordinate of this point
     17     private final int y; // y-coordinate of this point
     18 
     19     /**
     20      * Initializes a new point.
     21      *
     22      * @param  x the <em>x</em>-coordinate of the point
     23      * @param  y the <em>y</em>-coordinate of the point
     24      */
     25     public Point(int x, int y) {
     26         /* DO NOT MODIFY */
     27         this.x = x;
     28         this.y = y;
     29     }
     30 
     31     /**
     32      * Draws this point to standard draw.
     33      */
     34     public void draw() {
     35         /* DO NOT MODIFY */
     36         StdDraw.point(x, y);
     37     }
     38 
     39     /**
     40      * Draws the line segment between this point and the specified point
     41      * to standard draw.
     42      *
     43      * @param that the other point
     44      */
     45     public void drawTo(Point that) {
     46         /* DO NOT MODIFY */
     47         StdDraw.line(this.x, this.y, that.x, that.y);
     48     }
     49 
     50     /**
     51      * Returns the slope between this point and the specified point.
     52      * Formally, if the two points are (x0, y0) and (x1, y1), then the slope
     53      * is (y1 - y0) / (x1 - x0). For completeness, the slope is defined to be
     54      * +0.0 if the line segment connecting the two points is horizontal;
     55      * Double.POSITIVE_INFINITY if the line segment is vertical;
     56      * and Double.NEGATIVE_INFINITY if (x0, y0) and (x1, y1) are equal.
     57      *
     58      * @param  that the other point
     59      * @return the slope between this point and the specified point
     60      */
     61     public double slopeTo(Point that) {
     62         if ((this.x == that.x) && (this.y == that.y)) {
     63             return Double.NEGATIVE_INFINITY;
     64         } else if (this.x == that.x) {
     65             return Double.POSITIVE_INFINITY;
     66         } else if (this.y == that.y) {
     67             return 0;
     68         } else {
     69             return (that.y - this.y) / (double) (that.x - this.x);
     70         }
     71     }
     72 
     73     /**
     74      * Compares two points by y-coordinate, breaking ties by x-coordinate.
     75      * Formally, the invoking point (x0, y0) is less than the argument point
     76      * (x1, y1) if and only if either y0 < y1 or if y0 = y1 and x0 < x1.
     77      *
     78      * @param  that the other point
     79      * @return the value <tt>0</tt> if this point is equal to the argument
     80      *         point (x0 = x1 and y0 = y1);
     81      *         a negative integer if this point is less than the argument
     82      *         point; and a positive integer if this point is greater than the
     83      *         argument point
     84      */
     85     public int compareTo(Point that) {
     86         if ((this.x == that.x) && (this.y == that.y)) {
     87             return 0;
     88         } else if ((that.y > this.y) ||
     89                 ((that.y == this.y) && (that.x > this.x))) {
     90             return -1;
     91         } else {
     92             return 1;
     93         }
     94     }
     95 
     96     /**
     97      * Compares two points by the slope they make with this point.
     98      * The slope is defined as in the slopeTo() method.
     99      *
    100      * @return the Comparator that defines this ordering on points
    101      */
    102     public Comparator<Point> slopeOrder() {
    103         return new SlopeOrder(this);
    104     }
    105 
    106     /**
    107      * Returns a string representation of this point.
    108      * This method is provide for debugging;
    109      * your program should not rely on the format of the string representation.
    110      *
    111      * @return a string representation of this point
    112      */
    113     public String toString() {
    114         /* DO NOT MODIFY */
    115         return "(" + x + ", " + y + ")";
    116     }
    117 
    118     /**
    119      * Unit tests the Point data type.
    120      */
    121     public static void main(String[] args) {
    122         /* YOUR CODE HERE */
    123     }
    124 
    125     private class SlopeOrder implements Comparator<Point> {
    126         private Point p0;
    127 
    128         public SlopeOrder(Point invokePoint) {
    129             p0 = invokePoint;
    130         }
    131 
    132         public int compare(Point p1, Point p2) {
    133             double d01 = p0.slopeTo(p1);
    134             double d02 = p0.slopeTo(p2);
    135 
    136             if (d01 < d02) {
    137                 return -1;
    138             } else if (d01 > d02) {
    139                 return 1;
    140             } else {
    141                 return 0;
    142             }
    143         }
    144     }
    145 }
    Point
      1 import edu.princeton.cs.algs4.In;
      2 import edu.princeton.cs.algs4.StdDraw;
      3 import edu.princeton.cs.algs4.StdOut;
      4 import java.util.Arrays;
      5 
      6 public class BruteCollinearPoints {
      7     private int lineNumber;
      8     private Node last;
      9 
     10     public BruteCollinearPoints(Point[] points) // finds all line segments containing 4 points
     11      {
     12       
     13         if (points == null) {
     14             throw new NullPointerException();
     15         }
     16 
     17         lineNumber = 0;
     18 
     19         int num = points.length;
     20 
     21         Point[] clone = new Point[num];
     22         
     23         for (int i = 0; i < num; i++) {
     24             if (points[i] == null) {
     25                 throw new NullPointerException();
     26             }
     27 
     28             for (int j = i + 1; j < num; j++) {
     29                 if (points[i].compareTo(points[j]) == 0) {
     30                     throw new IllegalArgumentException();
     31                 }
     32             }
     33             clone[i] = points[i];
     34         }
     35         Arrays.sort(clone);
     36         for (int i = 0; i < num; i++) {
     37             for (int j = i+1; j < num; j++) {
     38                 for (int m = j+1; m < num; m++) {
     39                     for (int n = m+1; n < num; n++) {
     40                         double d01 = clone[i].slopeTo(clone[j]);
     41                         double d02 = clone[j].slopeTo(clone[m]);
     42                         double d03 = clone[m].slopeTo(clone[n]);
     43 
     44                         if (d01 == d02 && d02 == d03)  {
     45                             if (last != null) {
     46                                 Node newNode = new Node();
     47                                 newNode.prev = last;
     48                                 newNode.value = new LineSegment(clone[i],
     49                                         clone[n]);
     50                                 last = newNode;
     51                             } else {
     52                                 last = new Node();
     53                                 last.value = new LineSegment(clone[i],
     54                                         clone[n]);
     55                             }
     56 
     57                             lineNumber++;
     58                         }
     59                     }
     60                 }
     61             }
     62         }
     63     }
     64 
     65     public int numberOfSegments() // the number of line segments
     66      {
     67         return lineNumber;
     68     }
     69 
     70     public LineSegment[] segments() // the line segments
     71      {
     72         LineSegment[] lines = new LineSegment[lineNumber];
     73         Node current = last;
     74 
     75         for (int i = 0; i < lineNumber; i++) {
     76             lines[i] = current.value;
     77             current = current.prev;
     78         }
     79 
     80         return lines;
     81     }
     82 
     83     public static void main(String[] args) {
     84         // read the n points from a file
     85         In in = new In(args[0]);
     86         int n = in.readInt();
     87         Point[] points = new Point[n];
     88 
     89         for (int i = 0; i < n; i++) {
     90             int x = in.readInt();
     91             int y = in.readInt();
     92             points[i] = new Point(x, y);
     93         }
     94 
     95         // draw the points
     96         StdDraw.enableDoubleBuffering();
     97         StdDraw.setXscale(0, 32768);
     98         StdDraw.setYscale(0, 32768);
     99 
    100         for (Point p : points) {
    101             p.draw();
    102         }
    103 
    104         StdDraw.show();
    105 
    106         // print and draw the line segments
    107         BruteCollinearPoints collinear = new BruteCollinearPoints(points);
    108 
    109         for (LineSegment segment : collinear.segments()) {
    110             StdOut.println(segment);
    111             segment.draw();
    112         }
    113 
    114         StdDraw.show();
    115     }
    116 
    117     private class Node {
    118         private LineSegment value;
    119         private Node prev;
    120     }
    121 }
    BruteCollinearPoints
      1 import edu.princeton.cs.algs4.In;
      2 import edu.princeton.cs.algs4.StdDraw;
      3 import edu.princeton.cs.algs4.StdOut;
      4 
      5 import java.util.Arrays;
      6 
      7 public class FastCollinearPoints {
      8     private int lineNumber;
      9     private Node last;
     10 
     11     public FastCollinearPoints(Point[] points) // finds all line segments containing 4 or more points
     12      {
     13         if (points == null) {
     14             throw new NullPointerException();
     15         }
     16 
     17         lineNumber = 0;
     18 
     19         int num = points.length;
     20         Point[] clone = new Point[num];
     21 
     22         for (int i = 0; i < num; i++) {
     23             if (points[i] == null) {
     24                 throw new NullPointerException();
     25             }
     26 
     27             for (int j = i + 1; j < num; j++) {
     28                 if (points[i].compareTo(points[j]) == 0) {
     29                     throw new IllegalArgumentException();
     30                 }
     31             }
     32             clone[i] = points[i];
     33         }
     34         Arrays.sort(clone);
     35         
     36         if (num < 4) {
     37             return;
     38         }
     39 
     40         for (int i = 0; i < num - 1; i++) {
     41             int tempPointsNum = 0;
     42             Point[] tempPoints = new Point[num - 1];
     43 
     44             for (int j = 0; j < num; j++) {
     45                 if (i != j) tempPoints[tempPointsNum++] = clone[j];
     46             }
     47 
     48             Arrays.sort(tempPoints, clone[i].slopeOrder());
     49 
     50             int count = 0;
     51             Point min = null;
     52             Point max = null;
     53             
     54             for (int j = 0; j < (tempPointsNum - 1); j++) {
     55                 if (clone[i].slopeTo(tempPoints[j]) == clone[i].slopeTo(
     56                             tempPoints[j + 1])) {
     57                     if (min == null) {
     58                         if (clone[i].compareTo(tempPoints[j]) > 0) {
     59                             max = clone[i];
     60                             min = tempPoints[j];
     61                         } else {
     62                             max = tempPoints[j];
     63                             min = clone[i];
     64                         }
     65                     }
     66 
     67                     if (min.compareTo(tempPoints[j + 1]) > 0) {
     68                         min = tempPoints[j + 1];
     69                     }
     70 
     71                     if (max.compareTo(tempPoints[j + 1]) < 0) {
     72                         max = tempPoints[j + 1];
     73                     }
     74 
     75                     count++;
     76 
     77                     if (j == (tempPointsNum - 2)) {
     78                         if (count >= 2 && clone[i].compareTo(min) == 0) {
     79                             addLine(min, max);
     80                         }
     81 
     82                         count = 0;
     83                         min = null;
     84                         max = null;
     85                     }
     86                 } else {
     87                     if (count >= 2 && clone[i].compareTo(min) == 0) {
     88                         addLine(min, max);
     89                     }
     90 
     91                     count = 0;
     92                     min = null;
     93                     max = null;
     94                 }
     95             }
     96         }
     97     }
     98 
     99     private void addLine(Point a, Point b) {
    100         if (last != null) {
    101             Node newNode = new Node();
    102             newNode.prev = last;
    103             newNode.value = new LineSegment(a, b);
    104             last = newNode;
    105         } else {
    106             last = new Node();
    107             last.value = new LineSegment(a, b);
    108         }
    109         lineNumber++;
    110     }
    111 
    112     public int numberOfSegments() // the number of line segments
    113      {
    114         return lineNumber;
    115     }
    116 
    117     public LineSegment[] segments() // the line segments
    118      {
    119         LineSegment[] lines = new LineSegment[lineNumber];
    120         Node current = last;
    121 
    122         for (int i = 0; i < lineNumber; i++) {
    123             lines[i] = current.value;
    124             current = current.prev;
    125         }
    126 
    127         return lines;
    128     }
    129 
    130     public static void main(String[] args) {
    131         // read the n points from a file
    132         In in = new In(args[0]);
    133         int n = in.readInt();
    134         Point[] points = new Point[n];
    135 
    136         for (int i = 0; i < n; i++) {
    137             int x = in.readInt();
    138             int y = in.readInt();
    139             points[i] = new Point(x, y);
    140         }
    141 
    142         // draw the points
    143         StdDraw.enableDoubleBuffering();
    144         StdDraw.setXscale(0, 32768);
    145         StdDraw.setYscale(0, 32768);
    146 
    147         for (Point p : points) {
    148             p.draw();
    149         }
    150 
    151         StdDraw.show();
    152 
    153         // print and draw the line segments
    154         FastCollinearPoints collinear = new FastCollinearPoints(points);
    155 
    156         for (LineSegment segment : collinear.segments()) {
    157             StdOut.println(segment);
    158             segment.draw();
    159         }
    160 
    161         StdDraw.show();
    162     }
    163 
    164     private class Node {
    165         private LineSegment value;
    166         private Node prev;
    167     }
    168 }
    FastCollinearPoints
  • 相关阅读:
    两种三维点云密度聚类方法的研究与对比
    C++ string和char char*的转换
    七大排序算法总结
    map下标操作和insert区别
    c++ map 使用自定义结构做关键字
    BagFromImage安装与使用
    安装ipython notebook
    c++基本知识
    Python爬虫第一集
    91. Decode Ways
  • 原文地址:https://www.cnblogs.com/enigmaxp/p/5905658.html
Copyright © 2020-2023  润新知