149. Max Points on a Line

Description

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

Solution

HashMap

  • 平面里確定一條直線要兩個數(shù)據(jù),二維的直線可以用ax + b = y來表示灼捂,那么只需確定a和b就可以得到一條直線趾代。但是這道題這么做不方便殊鞭,表示直線還有其他方式,可以是兩個不同的點(高中數(shù)學做法)诀黍,也可以是一個點加一個斜率(這道題做法)
  • 斜率slope = (y2 - y1) / (x2 - x1),當 x1 == x2 時,分母為0滤港,斜率為無窮,表示和y軸平行的直線們
  • 在計算機里使用double表示斜率趴拧,是不嚴謹?shù)囊彩遣徽_的溅漾,double有精度誤差,double是有限的著榴,斜率是無限的添履,無法使用有限的double表示無限的斜率,不過此題的test case沒有涉及這個問題
  • 表示斜率最靠譜的方式是用最簡分數(shù)兄渺,即分子分母都無法再約分了缝龄。分子分母同時除以他們的最大公約數(shù)gcd(Greatest Common Divisor)即可得到最簡分數(shù)
  • gcd(a,b)汰现,一般求的是兩個正整數(shù)的gcd。這道題a和b有可能是0叔壤,分別表示與x軸或y軸平行的斜率(注意ab不能同時為0,表示同一個點沒有意義)瞎饲,所以這道題我們規(guī)定ab取值范圍:a>=0,b>=0。至于負數(shù)炼绘,先變成正數(shù)取gcd嗅战,再確定最終斜率的正負
  • gcd ( a , b )計算:歐幾里德算法又稱輾轉(zhuǎn)相除法,用于計算兩個整數(shù)a,b的最大公約數(shù)俺亮。其計算原理依賴于下面的定理:gcd(a,b) = gcd(b,a mod b)
  • 觀察gcd(a,b)驮捍,假設a,b為非負整數(shù):
    • a和b中有一個為零,那么gcd為另一個不為0的數(shù)脚曾;那么slope一定就會變成"+1/0"东且,在垂直經(jīng)過curr的直線上的所有點斜率都是這個!這樣是不是很好本讥,不用單獨處理斜率為infinite的情況了珊泳。
    • a和b都為0,gcd為0拷沸;

至于算法也沒什么色查,就是窮舉,對每個點撞芍,都計算一下該點和其他點連線的斜率秧了,這樣對于這個點來說,相同斜率的直線有多少條序无,就意味著有多少個點在同一條直線上验毡,因為這些直線是相同的。另外愉镰,如果計算過點A和點B的直線米罚,當算到點B時,就不用再和A連線了丈探,因為AB這條直線上的點數(shù)已經(jīng)都計算過了录择。這里,我們用哈希表碗降,以斜率為key隘竭,記錄有多少重復直線。

注意如果想要自定義Slope(斜率)類作為HashMap的Key的話要重寫hashCode()和equals()函數(shù)讼渊, 偷懶的話可以把斜率的分數(shù)表示成String作為Key动看,這樣就省了一些事。

hashmap的value的含義應定義為:過cur點以key為斜率的直線有幾個除了cur以外的點爪幻。在算完 過cur的所有直線后菱皆,統(tǒng)計cur點的總個數(shù)howManyCur须误,加到當前點最多的直線上,即可得到含cur點的最大直線上的點數(shù)仇轻。

/**
 * Definition for a point.
 * class Point {
 *     int x;
 *     int y;
 *     Point() { x = 0; y = 0; }
 *     Point(int a, int b) { x = a; y = b; }
 * }
 */
class Solution {
    public int maxPoints(Point[] points) {
        if (points == null) {
            return -1;
        }
        if (points.length < 2) {
            return points.length;
        }
        
        int max = 0;
        
        for (int i = 0; i < points.length; ++i) {
            Map<String, Integer> slope2Count = new HashMap<>();
            Point curr = points[i];
            int imax = 0;
            int currCount = 1;
            
            for (int j = i + 1; j < points.length; ++j) {
                Point q = points[j];
                // same point with curr
                if (q.x == curr.x && q.y == curr.y) {
                    ++currCount;
                    continue;
                }
                // different point
                String slope = getSlope(curr, q);
                slope2Count.put(slope, slope2Count.getOrDefault(slope, 0) + 1);
                imax = Math.max(slope2Count.get(slope), imax);
            }
            // don't forget to add the count of same point
            max = Math.max(imax + currCount, max);
        }
        
        return max;
    }
    // return slope as string for convenient
    private String getSlope(Point p, Point q) {
        long a = (long) q.x - p.x;
        long b = (long) q.y - p.y;
        String sign = getSign(a, b);
        a = Math.abs(a);
        b = Math.abs(b);
        long gcd = getGCD(a, b);    // use GCD to avoid losing accuracy
        return sign + a / gcd + "/" + b / gcd;
    }
    // return string sign
    private String getSign(long a, long b) {
        return (a > 0 && b < 0) || (a < 0 && b > 0) ? "-" : "+";
    }
    
    private long getGCD(long a, long b) {
        if (b == 0) {
            return a;
        }
        return getGCD(b, a % b);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末京痢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子篷店,更是在濱河造成了極大的恐慌祭椰,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疲陕,死亡現(xiàn)場離奇詭異方淤,居然都是意外死亡,警方通過查閱死者的電腦和手機蹄殃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門携茂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窃爷,你說我怎么就攤上這事邑蒋。” “怎么了按厘?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钱慢。 經(jīng)常有香客問我逮京,道長,這世上最難降的妖魔是什么束莫? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任懒棉,我火速辦了婚禮,結(jié)果婚禮上览绿,老公的妹妹穿的比我還像新娘策严。我一直安慰自己,他們只是感情好饿敲,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布妻导。 她就那樣靜靜地躺著,像睡著了一般怀各。 火紅的嫁衣襯著肌膚如雪倔韭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天瓢对,我揣著相機與錄音寿酌,去河邊找鬼。 笑死硕蛹,一個胖子當著我的面吹牛醇疼,可吹牛的內(nèi)容都是我干的硕并。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼秧荆,長吁一口氣:“原來是場噩夢啊……” “哼鲤孵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辰如,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤普监,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后琉兜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凯正,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年豌蟋,在試婚紗的時候發(fā)現(xiàn)自己被綠了廊散。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡梧疲,死狀恐怖允睹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幌氮,我是刑警寧澤缭受,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站该互,受9級特大地震影響米者,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宇智,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一蔓搞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧随橘,春花似錦喂分、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蜒车,卻和暖如春讳嘱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酿愧。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工沥潭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嬉挡。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓钝鸽,卻偏偏與公主長得像汇恤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拔恰,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359