1. 程式人生 > >一道面試題:比較兩個集合是否相等?

一道面試題:比較兩個集合是否相等?

先宣告:本文內容是偏向於應用開發的,分析解答過程不適用於純演算法研發崗位。

朋友小P近來參加某網際網路公司的電話面試,被問到一道題:怎麼判斷兩個集合是否相等?注意,這是面試官的原話,一字不多,一字不少。

小P迅速回答道用雜湊,對方在電話裡也沒有要求給出具體的解決方案,就問除了雜湊還有別的方法嗎?小P回答暫時沒想到別的方法,對方也沒繼續追問,就進入到其它題目的問答。

今天聊起時感覺這是道不錯的面試題:難度合適,可以根據不同的回答考察出不同型別的面試者,以及在整個展開的過程中可以初步瞭解到面試者水平層次,和其分析、解決問題的綜合能力。

小P的回答,其實不是讓人很滿意——起碼我是面試官的話我會覺得還有可以提升的地方。我不知道面試官的本意,但是在我看來,這麼簡短的一道題,應該本身就是設定了很多“坑”的——條件是缺失的,簡短的題目並沒有給出足夠多的資訊以便答題者“對症下藥”。當然,考慮到是電話面試,以及小P較為欠缺的面試經驗來看,其能迅速答出用雜湊應該也算反應快且基礎較為紮實。但是面試官沒有進一步的去考察,猜測可能是對小P的“快速解答”有所失望(或者說沒達到其預期),所以該題也就“點到為止”。

根據不同的面試職位,本題應該是有不同的側重點的。小P面的是偏業務、應用的開發工程師。對於一名應用工程師而言,當碰到這麼一道資訊不足的題時,想到的是怎麼來完善這些資訊,然後再根據不同的場景以給出最優方案。這時的溝通、分析、探討都很重要——其實還可以分享一個“祕密”:在一流的企業裡,coding這項技能,應該只佔應用開發工程師30%左右的比重,除此之外需要綜合考慮的“軟”能力還有很多。

回到這道題上。判斷兩個集合是否相等,我們最好先清楚這些:這是兩個什麼樣的集合?有序的還是無序的?裡面是有重複元素的還是已經各自去重的?集合的資料量大概是有多大?知道這個集合裡資料的大概範圍嗎?相等的定義是什麼?當兩個集合裡元素一樣時還要求其順序也一樣嗎?size==0的集合和null算相等嗎?

 (ps:思考一下,如果自己面試演算法類的,應該考慮到什麼鹽的問題??)

如果小P是按這個思路去跟面試官溝通,也許效果會更好。其實通過這些提問式的溝通,並不是說要炫我們的面試技巧,而是實事求是的去思考、分析題目。

如果說兩個集合是去重的小範圍內的正整數,那題目就退化的很簡單了:此時我們可以用一個輔助陣列來輕鬆解答。如集合A和集合B是落在[0,99]範圍的去重正整數集合,那麼new一個int[100]陣列t,然後掃一遍A,把t[A[i]]賦值為非零(陣列t的初始化各元素均為0)。再用一樣的操作對B掃一遍,不過此時是對t[B[i]]賦值為0。最後第三遍掃陣列t,如果t的元素還全是0則兩集合相等。時間複雜度O(n)。其實這個思路也類似於小P提到的雜湊,不過他回答的讓人感覺太過於草率,沒有任何分析,直接就答,搞的整個效果就是——你就那麼一問,我就這麼一答。

(ps:map比較)

繼續侃下這道題,如果沒有這麼多“恰當好處”的前提條件幫助,那又怎麼解決呢?其實誰都懂的一個演算法就是蠻力法:兩個集合裡的元素一一做比較唄。很多人看到這裡是很不屑的:這有什麼好答的。其實不然,最直觀的方法最不容易出錯。該題裡用蠻力法的話時間複雜度是O(n^2)。如果集合的元素個數不多(多少算多呢?),答題者直接回答這個也OK的——因為在我們最常用的JDK裡,集合類的equals方法,都是這麼實現的,我們來看下:

public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Set))
            return false;
        Collection c = (Collection) o;
        if (c.size() != size())
            return false;
        try {
            return containsAll(c);
        } catch (ClassCastException unused)   {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
    }

以上程式碼是JDK AbstractSet類裡equals方法的實現,如果跟進去看到最後發現就是一個蠻力法一一比較的,沒有什麼技巧。什麼,你不知道這個?JDK是最優秀的Java原始碼之一,你用Java沒理由不去研讀學習吧——不然確實是要對你的鑽研精神、技術熱情等持懷疑態度了——在優秀企業裡,想招的都是那種真正有N年工作經驗的人,而不是用一招鮮重複工作了N年的人。知其然更要知其所以然,這也是區分優秀者和平庸者的一個方法。

如果兩個需要比較的集合資料量特別大怎麼辦?這時候我們可以考慮用下預處理了:是否能對兩個集合提前排好序,然後在比較過程中查詢元素時是否要用上二分查詢?排序的開銷,和直接查詢的開銷,是否要根據不同的業務場景來做個折中?如果只是一次性的操作也許排序的意義不大,但如果是需要大量重複操作的呢?如果是集合不變的,以及集合經常會發生變化的,採用的策略也不一樣——經常發生變化的是否要去維護一個堆排序?

如果這道題是可以直接用現成第三方庫類的,那JDK裡已經有可以滿足的了。

雖然在純演算法方面我也沒能給出特別巧妙的解法,但我相信如果小P當時能按這個思路來回答,也許這道題就不會是草草收場,沒準能跟面試官一起討論出一個滿意的結局。如果有誰有特別好的思路,歡迎留言探討,共同進步。

相關推薦

一道試題比較集合是否相等

先宣告:本文內容是偏向於應用開發的,分析解答過程不適用於純演算法研發崗位。 朋友小P近來參加某網際網路公司的電話面試,被問到一道題:怎麼判斷兩個集合是否相等?注意,這是面試官的原話,一字不多,一字不少。 小P迅速回答道用雜湊,對方在電話裡也沒有要求給出具體的解決方案,就

Python學習 - 試題交換數字

# coding: utf-8 # 面試題:交換兩個數字 a = 6 b = 100 # solution 1 # c = a # a = b # b = c # solution 2 # a = a + b # b = a - b # a = a - b # solution

劍指Offer試題31.連結串列的第一公共節點

一、題目:兩個連結串列的第一個公共節點 題目:輸入兩個連結串列,找出它們的第一個公共結點。   連結串列結點定義如下,這裡使用C#語言描述: public class Node { public int key; public Node

19. 中興試題輸入整數n和m, 從數列1,2,...,n中任意選擇幾個數,使其和等於m, 要求編寫程式輸出所有的組合

2010年中興面試題程式設計求解:輸入兩個整數 n 和 m,從數列1,2,3.......n中隨意取幾個數, 使其和等於 m ,要求將其中所有的可能組合列出來. 分析: 可以使用遞迴思想, 從第n個數開始找其組合, 1)包括n的所有組合 2)不包括n的所有組合 把所有組

C語言比較字串是否相等

1) 使用strcmp進行比較 下面通過一個例子進行演示: #include <stdio.h> #include <string.h> int main(void) { char* str1 = "abc"; char* str2 = "a

matlab 比較集合是否相等 兒子的papa,papa的兒子

我覺得吧。平時工作效率不高,就是沒逼到。這個,兩天,也能編輯出一個垃圾著作權。 正事: 之前是通過兩個迴圈。matlab中提供很多很好的函式。比如setdiff a={'C'     'H'     'N'     'O'     'P'}; b={'Z','C','

一道試題通過wait和notify的執行緒互動輸出thread1-1...thread1-5,thread2-6...thread2-10...

這是一道關於多執行緒的面試題,好久沒有做過這種多執行緒的題了,手有點生,那麼就來敲一敲 package threadDemo; /* * 多執行緒的交叉列印 */ public class

試題----合並有序數組

合並 printf 面試 有序數組 color merge set ++ style #include<stdio.h> #include<string.h> #include<stdlib.h> void merge(int a[]

試題9-用棧來實現一個隊列,完成隊列的Push和Pop操作

ati import str highlight print row pty 用兩個棧 div 題目 用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素為int類型。 思路: 一個棧壓入元素,而另一個棧作為緩沖,將棧1的元素出棧後壓入棧2中

試題9-用棧來實現一個佇列,完成佇列的Push和Pop操作

題目 用兩個棧來實現一個佇列,完成佇列的Push和Pop操作。 佇列中的元素為int型別。 思路: 一個棧壓入元素,而另一個棧作為緩衝,將棧1的元素出棧後壓入棧2中 程式碼  import java.util.Stack;

【劍指offer】試題9:用棧實現佇列【C++版本】

題目: 用兩個棧實現佇列 用兩個棧實現一個佇列。佇列的宣告如下,請實現它的兩個成員函式,分別完成在佇列尾部插入節點和在佇列的頭部刪除節點 class solution { public: void push(int node);

一道試題說說程序和執行緒的區別

在理解這些概念之前首選要對併發有一定的感性認識,如果伺服器同一時間內只能服務於一個客戶端,其他客戶端都再那裡傻等的話,可見其效能的低下估計會被客戶罵出翔來,因此併發程式設計應運而生,併發是網路程式設計中必須考慮的問題。實現併發的方式有多種:比如多程序、多執行緒、IO多路複用。 在理解這些概念

Python 經典試題: a,b序列,大小都為n,序列元素的值任意整形數,無序, 要求: 通過交換a,b中的元素,使[序列a元素的和]與[序列b元素的和]之間的差最小 使

方法: 用隨機數來求出結果 解題思想: 用隨機數隨機出來所有的程式碼排列可能性,在定義次數的時候 定義的次數越大得到的結果越準確. 最終程式碼: import random #有很多方法是把兩個列表合成一個後排序按照一大一小的分配生成兩個列表 #但是這樣是在資

使用LINQ、Lambda 表示式 、委託快速比較集合,找出需要新增、修改、刪除的物件

本文需要對C#裡的LINQ、Lambda 表示式 、委託有一定了解。 在工作中,經常遇到需要對比兩個集合的場景,如: 頁面集合資料修改,需要儲存到資料庫 全量同步上游資料到本系統資料庫 在這些場景中,需要識別出需要新增、更新、刪除的資料,由於每次應用是,需要比較的物件型別不一致,因此寫了個相對通用的方

牛客網線上程式設計專題《劍指offer-試題37》連結串列的第一公共結點

題目連結: 題目描述: 解題思路: 首先遍歷兩個連結串列得到它們的長度,就能知道哪個連結串列比較長,以及長的連結串列比短的連結串列多幾個結點。在第二次遍歷的時候,在較長的連結串列上先走若干步,接著再同時在兩個連結串列上遍歷,找到的第一個相同的結點就是它們的第

C語言strcmp比較字串是否相等

#include<stdio.h> #include<string.h> //比較兩個字串是否相等,(或者說前字串比後字串不同的地方大幾) int My_strcmp( const char *str1

Java比較物件中全部屬性值是否相等

Java:比較兩個物件中全部屬性值是否相等 例如下述Java類: import java.io.Serializable; import java.util.List; public class Bean_Topology implements Serial

今天做到一道試題關於堆記憶體與棧記憶體的區別

java中記憶體分配策略及堆和棧的比較   1 記憶體分配策略   按照編譯原理的觀點,程式執行時的記憶體分配有三種策略,分別是靜態的,棧式的,和堆式的.   靜態儲存分配是指在編譯時就能確定每個資料目標在執行時刻的儲存空間需求,因而在編譯時就可以給他們分配固定的記憶體空間.這種分配策略要求程式程式碼中

C/C++試題—使用STL佇列實現一個棧

題目介紹 使用STL中的兩個佇列實現一個棧,實現棧的top、pop、push、clear等操作。 思路分析 思路和使用2個棧實現一個佇列是相通的,用一個佇列queue1容器用來 壓棧,出棧的時候判斷queue1.size()是否大於1,大於1的話隊尾元

經典試題——求任意葉節點中最近的父節點

以下程式未經測試,僅供參考! #include <iostream> #include <vector> using namespace std; struct LCATreeNode{   LCATreeNode* m_pLeft;   LC