Leetcode刷題 2021.01.13
阿新 • • 發佈:2021-01-14
技術標籤:刷題
Leetcode刷題 2021.01.13
Leetcode684 冗餘連線
在本問題中, 樹指的是一個連通且無環的無向圖。
輸入一個圖,該圖由一個有著N個節點 (節點值不重複1, 2, …, N) 的樹及一條附加的邊構成。附加的邊的兩個頂點包含在1到N中間,這條附加的邊不屬於樹中已存在的邊。
結果圖是一個以邊組成的二維陣列。每一個邊的元素是一對[u, v] ,滿足 u < v,表示連線頂點u 和v的無向圖的邊。
返回一條可以刪去的邊,使得結果圖是一個有著N個節點的樹。如果有多個答案,則返回二維陣列中最後出現的邊。答案邊 [u, v] 應滿足相同的格式 u < v。
圖論月,彳亍。又是並查集,如果上週做的話可能都無從下手,現在做就是並查集模板了。
class Solution {
public int[] findRedundantConnection(int[][] edges) {
if (edges == null || edges.length == 0) return new int[]{0, 0};
//沒什麼好註釋的,並查集模板題。。
int n = edges.length + 1;
UnionFind uf = new UnionFind(n);
for (int i = 0; i < edges.length; i++){
int x = edges[i][0], y = edges[i][1];
if (!uf.union(x, y)){
return new int[]{x, y};
}
}
return new int[]{0, 0};
}
class UnionFind{
int[] parent;
public UnionFind(int n){
parent = new int[n];
for(int i = 0; i < n; i++){
parent[i] = i;
}
}
private int find(int i){
if(parent[i] == i){
return parent[i];
}
return parent[i] = find(parent[i]);
}
private boolean union(int i, int j){
int root1 = find(i);
int root2 = find(j);
if (root1 == root2) return false;
parent[root1] = parent[root2];
return true;
}
}
}
Leetcode210 元素和小於等於閾值的正方形的最大邊長
現在你總共有 n 門課需要選,記為 0 到 n-1。
在選修某些課程之前需要一些先修課程。 例如,想要學習課程 0 ,你需要先完成課程 1 ,我們用一個匹配來表示他們: [0,1]
給定課程總量以及它們的先決條件,返回你為了學完所有課程所安排的學習順序。
可能會有多個正確的順序,你只要返回一種就可以了。如果不可能完成所有課程,返回一個空陣列。
昨天的每日一題不會做,但是拓撲排序還是學了下。看了Liweiwei的題解,主要還是使用廣度優先遍歷,將入度為0的點一一入隊即可。
class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
if (numCourses <= 0) return new int[0];
//宣告鄰接表,用list陣列表示
List<Integer>[] adj = new ArrayList[numCourses];
//初始化一下
for(int i = 0; i < numCourses; i++){
adj[i] = new ArrayList<>();
}
//每個結點的入度表
int[] indegree = new int[numCourses];
//如果有p[1]指向p[0]的邊,就新增到鄰接表,並且p[0]的入度加1.
for(int[] p : prerequisites){
adj[p[1]].add(p[0]);
indegree[p[0]]++;
}
//結果陣列
int[] res = new int[numCourses];
//廣度優先使用佇列
Queue<Integer> queue = new LinkedList<>();
//入度為0的點入隊
for(int i = 0; i < numCourses; i++){
if (indegree[i] == 0){
queue.offer(i);
}
}
//結果個數
int count = 0;
while (!queue.isEmpty()){
//出隊
Integer temp = queue.poll();
//放到結果集
res[count++] = temp;
//遍歷出隊元素的鄰接表,把這些點的入度都減一
for(int ele : adj[temp]){
indegree[ele]--;
//如果入度為0,入隊
if (indegree[ele] == 0){
queue.offer(ele);
}
}
}
//count == numCourses說明有結果
if (count == numCourses){
return res;
}
//沒有結果返回空陣列
return new int[0];
}
}
Leetcode1669 合併兩個連結串列
給你兩個連結串列 list1 和 list2 ,它們包含的元素分別為 n 個和 m 個。
請你將 list1 中第 a 個節點到第 b 個節點刪除,並將list2 接在被刪除節點的位置。
連結串列題還是比較簡單的吧,無非考慮邊界,還有index位置。這種交換順序的題目,不行就多用幾個輔助結點。這題好像有一定的特殊性,邊界問題不需要考慮很多。
class Solution {
public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) {
//偽節點,連結串列題的常見套路了
ListNode dummyHead = new ListNode(0);
dummyHead.next = list1;
ListNode cur = dummyHead;
ListNode prevHead = null;
ListNode prevTail = null;
//先找a的位置的前一個結點,和b結點的後一個位置
for(int i = 0; i < b + 2; i++){
if (i == a) prevHead = cur;
cur = cur.next;
}
prevTail = cur;
//再找list的尾結點
ListNode cur2 = list2, prev = null;
while (cur2 != null){
prev = cur2;
cur2 = cur2.next;
}
//兩個鏈上就行
prevHead.next = list2;
prev.next = prevTail;
return dummyHead.next;
}
}