1. 程式人生 > 其它 >Leetcode刷題 2021.01.13

Leetcode刷題 2021.01.13

技術標籤:刷題

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;
    }
}