C#刷遍Leetcode面試題系列連載(5):No.593 - 有效的正方形


上一篇 LeetCode 面試題中,我們分析了一道難度為 Easy 的數學題 - 自除數,提供了兩種方法。今天我們來分析一道難度為 Medium 的面試題。

img

系列教程索引

傳送門:https://enjoy233.cnblogs.com/articles/leetcode_csharp_index.html

  1. C#刷遍Leetcode面試題系列連載(1) - 入門與工具簡介
  2. C#刷遍Leetcode面試題系列連載(2): No.38 - 報數
  3. C# 刷遍 Leetcode 面試題系列連載(3): No.728 - 自除數
  4. C#刷遍Leetcode面試題系列連載(4):No.633 - 平方數之和
  5. C#刷遍Leetcode面試題系列連載(5):No.593 - 有效的正方形

今天要給大家分析的面試題是 LeetCode 上第 593 號問題,

LeetCode - 593. 有效的正方形

https://leetcode-cn.com/problems/valid-square

題目描述

給定二維空間中四點的坐標,返回四點是否可以構造一個正方形。

一個點的坐標(x,y)由一個有兩個整數的整數數組表示。

示例:

輸入: p1 = [0,0], p2 = [1,1], p3 = [1,0], p4 = [0,1]
輸出: True

注意:

  1. 所有輸入整數都在 [-10000,10000] 范圍內。
  2. 一個有效的正方形有四個等長的正長和四個等角(90度角)。
  3. 輸入點沒有順序。

解題思路:

可以基於正方形的特征來判斷~

方法1: 由於點是以坐標形式給出的,於是可以圍繞向量垂直以及對角線長度的平方為邊長平方的 2 倍來做.

而向量垂直地判定依據是向量點乘的乘積為0)。


方法2: 判斷兩組平行邊長度相等,對角線長度相等,且至少一對鄰邊長度相等. (有下圖兩種情形,p1、p2兩個點相鄰或不相鄰)
dotNET匠人 - 示意圖

方法3: 所有鄰邊+對角線中,如果是正方形會有2種長度,如果是菱形,會有3種長度, 平行四邊形(含長方形)有4種長度, 其他非平行四邊形有6種長度。於是只需要使用一個set,滿足:

  • 輸入中不存在相同的點,即任意兩點的距離不為0
  • set中恰好有兩種長度.

臨界情況: 4個輸入的點中有兩個或多個相同,直接返回false。


方法1 已AC代碼:

public class Solution
{
    public bool ValidSquare(int[] p1, int[] p2, int[] p3, int[] p4)
    {
        int[] vect1 = { p2[0] - p1[0], p2[1] - p1[1] };
        int[] vect2 = { p4[0] - p1[0], p4[1] - p1[1] };
        int[] vect3 = { p3[0] - p1[0], p3[1] - p1[1] };
        List<int[]> vects = new List<int[]> { vect1, vect2, vect3 };

        if (vects.Any(x => x.SequenceEqual(new[]{0, 0}))) // 輸入的點中存在相同的, 即有(0, 0)的向量
            return false;

        List<int> lenSquaresFromP1 = new List<int> { GetLenSquare(p2, p1), GetLenSquare(p4, p1), GetLenSquare(p3, p1) };
        List<int> extraLenSquares = new List<int> { GetLenSquare(p2, p3), GetLenSquare(p2, p4), GetLenSquare(p3, p4) };

        if (lenSquaresFromP1.Max() != extraLenSquares.Max())
            return false; // 當從p1出發的最長距離不為所有點兩兩之間距離的最大值時,只是菱形,不是正方形

        var maxLenSquare = lenSquaresFromP1.Max(); // 后面要remove, 此處作備份
        int maxPos = lenSquaresFromP1.IndexOf(maxLenSquare);
        lenSquaresFromP1.RemoveAt(maxPos);
        vects.RemoveAt(maxPos);

        if (lenSquaresFromP1[0] == lenSquaresFromP1[1] && lenSquaresFromP1[0] * 2 == maxLenSquare &&
            VectorCross(vects[0], vects[1]) == 0)
            return true;

        return false;
    }

    private int VectorCross(int[] vect1, int[] vect2) => vect1[0] * vect2[0] +
                                                         vect1[1] * vect2[1];

    private int GetLenSquare(int[] point1, int[] point2) => (point2[0] - point1[0]) * (point2[0] - point1[0]) +
                                                         (point2[1] - point1[1]) * (point2[1] - point1[1]);
}

執行用時: 104 ms, 在所有 csharp 提交中擊敗了80.00%的用戶.


方法2 已AC代碼:

public class Solution
{
    public bool ValidSquare(int[] p1, int[] p2, int[] p3, int[] p4)
    {
        if (GetLenSquare(p1, p2) == 0 || GetLenSquare(p2, p3) == 0 || GetLenSquare(p3, p4) == 0 || GetLenSquare(p1, p4) == 0)
            return false;

        return GetLenSquare(p1, p2) == GetLenSquare(p3, p4) && GetLenSquare(p1, p3) == GetLenSquare(p2, p4) && GetLenSquare(p1, p4) == GetLenSquare(p2, p3) &&
               (GetLenSquare(p1, p2) == GetLenSquare(p1, p3) || GetLenSquare(p1, p2) == GetLenSquare(p1, p4) || GetLenSquare(p1, p3) == GetLenSquare(p1, p4));
    }

    private int GetLenSquare(int[] point1, int[] point2) => (point2[0] - point1[0]) * (point2[0] - point1[0]) +
                                                         (point2[1] - point1[1]) * (point2[1] - point1[1]);
}

執行用時: 108 ms, 在所有 csharp 提交中擊敗了80.00%的用戶.


方法3 已AC代碼:

public class Solution
{
    public bool ValidSquare(int[] p1, int[] p2, int[] p3, int[] p4)
    {
        HashSet<int> set = new HashSet<int>
        {
            GetLenSquare(p1, p2),
            GetLenSquare(p1, p3),
            GetLenSquare(p1, p4),
            GetLenSquare(p2, p3),
            GetLenSquare(p2, p4),
            GetLenSquare(p3, p4)
        };

        if (!set.Any(x => x == 0) && set.Count == 2)  // 所有鄰邊+對角線中,菱形有3種長度, 平行四邊形(含長方形)有4種長度, 其他四邊形有6種長度 
        {
            return true;
        }

        return false;
    }

    private int GetLenSquare(int[] point1, int[] point2) => (point2[0] - point1[0]) * (point2[0] - point1[0]) + (point2[1] - point1[1]) * (point2[1] - point1[1]);
}

執行用時: 104 ms, 在所有 csharp 提交中擊敗了 90.91% 的用戶


歡迎提出更佳的解決思路~



作者簡介:Bravo Yeung,計算機碩士,知乎干貨答主(獲81K 贊同, 38K 感謝, 235K 收藏)。曾在國內 Top3互聯網視頻直播公司工作過,后加入一家外企做軟件開發至今。


如需轉載,請加微信 iMath7 申請開白!


歡迎在留言區留下你的觀點,一起討論提高。如果今天的文章讓你有新的啟發,學習能力的提升上有新的認識,歡迎轉發分享給更多人。


歡迎各位讀者加入 .NET技術交流群,在公眾號后台回復“加群”或者“學習”即可。


大白技術控 公眾號名片

文末彩蛋

微信后台回復“asp”,給你:一份全網最強的ASP.NET學習路線圖。


回復“cs”,給你:一整套 C# 和 WPF 學習資源!


回復“core”,給你:2019年dotConf大會上發布的.NET core 3.0學習視頻!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM