第一次玩這個,聽說比周賽簡單點,這次一共四道題,發現自己圖論是真不會。
後面兩題,第三題是裸的最小生成樹,第四題是裸的拓撲排序。
- 最大唯一數 顯示英文描述
用戶通過次數 302
用戶嘗試次數 313
通過次數 307
提交次數 525
題目難度 Easy
給你一個整數數組 A,請找出並返回在該數組中僅出現一次的最大整數。
如果不存在這個只出現一次的整數,則返回 -1。
示例 1:
輸入:[5,7,3,9,4,9,8,3,1]
輸出:8
解釋:
數組中最大的整數是 9,但它在數組中重複出現了。而第二大的整數是 8,它只出現了一次,所以答案是 8。
示例 2:
輸入:[9,9,8,8]
輸出:-1
解釋:
數組中不存在僅出現一次的整數。
提示:
1 <= A.length <= 2000
0 <= A[i] <= 1000
分析:
這題有兩種思路比較常見,我已開始用排序做…結果錯了好幾次,後面乾脆用hash表讀一下算了。
解法一:
排序後遍歷
class Solution {
public:
int largestUniqueNumber(vector<int>& A) {
sort(A.begin(), A.end());
if(A.size() == 1) {
return A[0];
}
for(int i = A.size()-1; i >= 0; i--) {
if(i < A.size() -1 && A[i] == A[i+1]) {
continue;
}
if(i == 0 || A[i] != A[i-1]) {
return A[i];
}
}
return -1;
}
};
解法二:
hash
class Solution {
public:
int largestUniqueNumber(vector<int>& A) {
unordered_map<int, int> map;
for(int i = 0; i < A.size(); i++) {
map[A[i]]++;
}
for(int i = 1000; i >=0; i--) {
if(map[i] == 1) {
return i;
}
}
return -1;
}
};
- 阿姆斯特朗數 顯示英文描述
用戶通過次數 301
用戶嘗試次數 304
通過次數 306
提交次數 388
題目難度 Easy
假設存在一個 k 位數 N,其每一位上的數字的 k 次冪的總和也是 N,那麼這個數是阿姆斯特朗數。
給你一個正整數 N,讓你來判定他是否是阿姆斯特朗數,是則返回 true,不是則返回 false。
示例 1:
輸入:153
輸出:true
示例:
153 是一個 3 位數,且 153 = 1^3 + 5^3 + 3^3。
示例 2:
輸入:123
輸出:false
解釋:
123 是一個 3 位數,且 123 != 1^3 + 2^3 + 3^3 = 36。
提示:
1 <= N <= 10^8
class Solution {
public:
bool isArmstrong(int N) {
int num = 0;
int temp1 = N;
while(N) {
N = N / 10;
num++;
}
N = temp1;
int temp = 0, sum = 0;
while(N) {
temp = N % 10;
sum += pow(temp, num);
N = N / 10;
}
return sum == temp1;
}
};
- 最低成本聯通所有城市 顯示英文描述
用戶通過次數 79
用戶嘗試次數 148
通過次數 87
提交次數 535
題目難度 Medium
想象一下你是個城市基建規劃者,地圖上有 N 座城市,它們按以 1 到 N 的次序編號。
給你一些可連接的選項 conections,其中每個選項 conections[i] = [city1, city2, cost] 表示將城市 city1 和城市 city2 連接所要的成本。(連接是雙向的,也就是說城市 city1 和城市 city2 相連也同樣意味着城市 city2 和城市 city1 相連)。
返回使得每對城市間都存在將它們連接在一起的連通路徑(可能長度爲 1 的)最小成本。該最小成本應該是所用全部連接代價的綜合。如果根據已知條件無法完成該項任務,則請你返回 -1。
示例 1:
輸入:N = 3, conections = [[1,2,5],[1,3,6],[2,3,1]]
輸出:6
解釋:
選出任意 2 條邊都可以連接所有城市,我們從中選取成本最小的 2 條。
示例 2:
輸入:N = 4, conections = [[1,2,3],[3,4,4]]
輸出:-1
解釋:
即使連通所有的邊,也無法連接所有城市。
提示:
1 <= N <= 10000
1 <= conections.length <= 10000
1 <= conections[i][0], conections[i][1] <= N
0 <= conections[i][2] <= 10^5
conections[i][0] != conections[i][1]
分析:
明確一下方向,求最小生成樹一共有兩種算法:prim算法和Kruskal算法。
prim算法適合稠密圖,時間複雜度爲O(n^2),n爲結點數
Kruskal算法適合稀疏圖,時間複雜度爲O(eloge),e爲邊數
上面的題目屬於稀疏圖,選擇Kruskal算法。
//並查集可以通過查詢兩個結點所在集合的根結點是否相同來判斷他們是否在同一個集合
//而只要把測試邊的兩個端點所在集合合併,就能達到將邊加入最小生成樹的效果
class UnionSet{
public:
vector<int> father;
UnionSet(int n) {
father.resize(n+1);
for(int i = 1; i <= n; i++) {
father[i] = i;
}
}
int find(int x) {
while(father[x] != x) {
x = father[x];
}
return x;
}
void insert(int x, int y) {
father[find(x)] = y;
}
// int count() {
// int cnt = 0;
// for(int i = 1; i <= father.size(); i++) {
// if(father[i] == i) {
// cnt++;
// }
// }
// return cnt;
// }
};
class Solution {
public:
//const static int maxv = 10002;
static bool cmp(vector<int>& e1, vector<int>& e2) {
return e1[2] < e2[2];
}
int minimumCost(int N, vector<vector<int>>& conections) {
UnionSet un = UnionSet(N);
//對所有邊按邊權從小到大排序
sort(conections.begin(), conections.end(), cmp);
int sum = 0;
int cnt = 0;
for(int i = 0; i < conections.size(); i++) {
//按邊權從小到大測試所有邊,如果當前測試邊所連接的兩個頂點不在同一個連通塊中,則把這條測試邊加入到當前最小生成樹中;否則,將邊捨棄
if(un.find(conections[i][0]) != un.find(conections[i][1])) {
un.insert(conections[i][0], conections[i][1]);
cnt++;
sum += conections[i][2];
}
}
//直到最小生成樹中的邊數等於總頂點數減1或是測試完所有邊時結束
if(cnt == N - 1) {
return sum;
} else {
return -1;
}
}
};
- 平行課程 顯示英文描述
用戶通過次數 101
用戶嘗試次數 127
通過次數 104
提交次數 221
題目難度 Hard
已知有 N 門課程,它們以 1 到 N 進行編號。
給你一份課程關係表 relations[i] = [X, Y],用以表示課程 X 和課程 Y 之間的先修關係:課程 X 必須在課程 Y 之前修完。
假設在一個學期裏,你可以學習任何數量的課程,但前提是你已經學習了將要學習的這些課程的所有先修課程。
請你返回學完全部課程所需的最少學期數。
如果沒有辦法做到學完全部這些課程的話,就返回 -1。
示例 1:
輸入:N = 3, relations = [[1,3],[2,3]]
輸出:2
解釋:
在第一個學期學習課程 1 和 2,在第二個學期學習課程 3。
示例 2:
輸入:N = 3, relations = [[1,2],[2,3],[3,1]]
輸出:-1
解釋:
沒有課程可以學習,因爲它們相互依賴。
提示:
1 <= N <= 5000
1 <= relations.length <= 5000
relations[i][0] != relations[i][1]
輸入中沒有重複的關係
思路:
求解拓撲序列:
- 定義一個隊列q,並把所有入度爲0的結點加入隊列
- 取隊首結點,輸出。然後刪去所有從它出發的邊,並令這些邊到達的頂點的入度減1,如果某個頂點的入度減爲0,則將其加入隊列。
- 反覆進行2操作,直到隊列爲空。如果隊列爲空時入隊的結點數目恰好爲n,說明拓撲排序成功,圖G爲有向無環圖;
否則,拓撲排序失敗,圖G中有環。
class Solution {
private:
int const static maxv = 5001;
public:
int minimumSemesters(int N, vector<vector<int>>& relations) {
int num = 0;
queue<int> q;
int inD[maxv];
vector<int> edge[maxv];
memset(inD, 0, sizeof(inD));
for(int i = 0; i < relations.size(); i++) {
inD[relations[i][1]]++;
edge[relations[i][0]].push_back(relations[i][1]);
}
int b[maxv];
int res = 0;
memset(b, 0, sizeof(b));
for(int i = 1; i <= N; i++) {
if(inD[i] == 0) {
q.push(i);
b[i] = 1;
res = 1;
num++;
}
}
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = 0; i < edge[u].size(); i++) {
int v = edge[u][i];
inD[v]--;
if(inD[v] == 0) {
q.push(v);
b[v] = b[u] + 1;
res = b[u] + 1;
num++;
}
}
}
if(num == N) {
return res;
} else {
return -1;
}
}
};