1. 程式人生 > 其它 >LeetCode 周賽223

LeetCode 周賽223

技術標籤:# leetcode

在這裡插入圖片描述
考完試,康復訓練一下

5649. 解碼異或後的陣列

未知 整數陣列 arr 由 n 個非負整陣列成。

經編碼後變為長度為 n - 1 的另一個整數陣列 encoded ,其中 encoded[i] = arr[i] XOR arr[i + 1] 。例如,arr = [1,0,2,1] 經編碼後得到 encoded = [1,2,3] 。

給你編碼後的陣列 encoded 和原陣列 arr 的第一個元素 first(arr[0])。

請解碼返回原陣列 arr 。可以證明答案存在並且是唯一的。

示例 1:

輸入:encoded = [1,2,3], first = 1

輸出:[1,0,2,1]
解釋:若 arr = [1,0,2,1] ,那麼 first = 1 且 encoded = [1 XOR 0, 0 XOR 2, 2 XOR 1] = [1,2,3]
示例 2:

輸入:encoded = [6,2,7,3], first = 4
輸出:[4,2,0,7,4]

提示:

2 <= n <= 104
encoded.length == n - 1
0 <= encoded[i] <= 105
0 <= first <= 105

思路:
因為 x ⊕ x = 0 x ⊕ x=0 xx=0,所以 a [ i ] ⊕ e n c o d e d [ i ] = a [ i + 1 ] a[i]⊕encoded[i]=a[i+1]

a[i]encoded[i]=a[i+1]

class Solution {
public:
    vector<int> decode(vector<int>& encoded, int first) {
        vector<int>ans;
        ans.push_back(first);
        for(int i = 0;i < encoded.size();i++) {
            ans.push_back(ans.back() ^ encoded[i]);
        }
        return
ans; } };

5652. 交換連結串列中的節點

給你連結串列的頭節點 head 和一個整數 k 。

交換 連結串列正數第 k 個節點和倒數第 k 個節點的值後,返回連結串列的頭節點(連結串列 從 1 開始索引)。

示例 1:
輸入:head = [1,2,3,4,5], k = 2
輸出:[1,4,3,2,5]
示例 2:

輸入:head = [7,9,6,6,7,8,3,0,9,5], k = 5
輸出:[7,9,6,6,8,7,3,0,9,5]
示例 3:

輸入:head = [1], k = 1
輸出:[1]
示例 4:

輸入:head = [1,2], k = 1
輸出:[2,1]
示例 5:

輸入:head = [1,2,3], k = 2
輸出:[1,2,3]

思路:
對連結串列不是很熟悉,所以用的很暴力的做法,就是把連結串列拆到數組裡面,然後找到第k個數和倒數第k個數,再遍歷一次連結串列交換。(連結串列沒有前向指標,所以也沒想到什麼優雅的做法)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapNodes(ListNode* head, int k) {
        vector<int>num;
        ListNode*h1 = head;
        while(h1 != NULL) {
            num.push_back(h1->val);
            h1 = h1->next;
        }
        int n = num.size();
        ListNode*h2 = head;
        int cnt = 0;
        while(h2 != NULL) {
            if(cnt == k - 1) {
                h2 -> val = num[n - k];
            } else if(cnt == n - k) {
                h2 -> val = num[k - 1];
            }
            cnt++;
            h2 = h2->next;
        }
        return head;
    }
};

5650. 執行交換操作後的最小漢明距離

題目難度Medium
給你兩個整數陣列 source 和 target ,長度都是 n 。還有一個數組 allowedSwaps ,其中每個 allowedSwaps[i] = [ai, bi] 表示你可以交換陣列 source 中下標為 ai 和 bi(下標從 0 開始)的兩個元素。注意,你可以按 任意 順序 多次 交換一對特定下標指向的元素。

相同長度的兩個陣列 source 和 target 間的 漢明距離 是元素不同的下標數量。形式上,其值等於滿足 source[i] != target[i] (下標從 0 開始)的下標 i(0 <= i <= n-1)的數量。

在對陣列 source 執行 任意 數量的交換操作後,返回 source 和 target 間的 最小漢明距離 。

示例 1:

輸入:source = [1,2,3,4], target = [2,1,4,5], allowedSwaps = [[0,1],[2,3]]
輸出:1
解釋:source 可以按下述方式轉換:

  • 交換下標 0 和 1 指向的元素:source = [2,1,3,4]
  • 交換下標 2 和 3 指向的元素:source = [2,1,4,3]
    source 和 target 間的漢明距離是 1 ,二者有 1 處元素不同,在下標 3 。
    示例 2:

輸入:source = [1,2,3,4], target = [1,3,2,4], allowedSwaps = []
輸出:2
解釋:不能對 source 執行交換操作。
source 和 target 間的漢明距離是 2 ,二者有 2 處元素不同,在下標 1 和下標 2 。
示例 3:

輸入:source = [5,1,2,4,3], target = [1,5,4,2,3], allowedSwaps = [[0,4],[4,2],[1,3],[1,4]]
輸出:0

提示:

n == source.length == target.length
1 <= n <= 105
1 <= source[i], target[i] <= 105
0 <= allowedSwaps.length <= 105
allowedSwaps[i].length == 2
0 <= ai, bi <= n - 1
ai != bi

思路:
能交換的下標部分用並查集連起來,然後用一個 m a p map map標記這個並查集裡面有哪些數。遍歷 t a r g e t target target陣列,看 t a r g e t [ i ] target[i] target[i]對於下標 i i i的並查集中,是否存在 t a r g e t [ i ] target[i] target[i]這個數;如果存在,那麼直接換過來(具體過程咱不考慮),然後 m p [ r o o t [ i ] ] [ t a r g e t [ i ] ] − − mp[root[i]][target[i]]-- mp[root[i]][target[i]]。否則就說明 t a r g e t [ i ] target[i] target[i]一定不等於 s o u r c e [ i ] source[i] source[i],那麼海明距離 a n s + + ans++ ans++

class Solution {
public:
    int fa[100005];
    map<int,int>mp[100005];
    int findset(int x) {
        if(x == fa[x]) return x;
        return fa[x] = findset(fa[x]);
    }
    void Union(int x,int y) {
        int fx = findset(x),fy = findset(y);
        if(fx != fy) fa[fx] = fy;
    }
    int minimumHammingDistance(vector<int>& source, vector<int>& target, vector<vector<int>>& allowedSwaps) {
        int n = source.size();
        for(int i = 0;i < n;i++) {
            fa[i] = i;
            mp[i].clear();
        }
        for(int i = 0;i < allowedSwaps.size();i++) {
            int x = allowedSwaps[i][0],y = allowedSwaps[i][1];
            Union(x,y);
        }
        for(int i = 0;i < n;i++) {
            int x = findset(i);
            mp[x][source[i]]++;
        }
        int ans = 0;
        for(int i = 0;i < n;i++) {
            int x = findset(i);
            if(mp[x][target[i]]) {
                mp[x][target[i]]--;
            } else {
                ans++;
            }
        }
        return ans;
    }
};

5639. 完成所有工作的最短時間

題目難度Hard
給你一個整數陣列 jobs ,其中 jobs[i] 是完成第 i 項工作要花費的時間。

請你將這些工作分配給 k 位工人。所有工作都應該分配給工人,且每項工作只能分配給一位工人。工人的 工作時間 是完成分配給他們的所有工作花費時間的總和。請你設計一套最佳的工作分配方案,使工人的 最大工作時間 得以 最小化 。

返回分配方案中儘可能 最小 的 最大工作時間 。

示例 1:

輸入:jobs = [3,2,3], k = 3
輸出:3
解釋:給每位工人分配一項工作,最大工作時間是 3 。
示例 2:

輸入:jobs = [1,2,4,7,8], k = 2
輸出:11
解釋:按下述方式分配工作:
1 號工人:1、2、8(工作時間 = 1 + 2 + 8 = 11)
2 號工人:4、7(工作時間 = 4 + 7 = 11)
最大工作時間是 11 。

提示:

1 <= k <= jobs.length <= 12
1 <= jobs[i] <= 107

思路:

  • 一看這範圍:12,不是搜尋就是狀壓,衝啊。
  • 一算複雜度,爆搜是 n k n^k nk,如果k≤5,那麼 5 12 = 244140625 5^{12}=244140625 512=244140625,再剪剪枝還是可以接受的。但是 k k k再往上按照爆搜的寫法就肯定不行的了,咋優化?
  • 一個很明顯的事實就是, k ≥ n + 1 2 k≥\frac{n+1}{2} k2n+1的時候,最大的結果不可能超過 j o b s jobs jobs陣列兩兩匹配的結果。而要使最大值最小,我們肯定不會讓 j o b s jobs jobs陣列最大的 k k k個數兩兩匹配,所以一開始就將最大的 k k k個數分給不同的工人。此時 n = n − k n=n-k n=nk,複雜度此時最大 5 12 5^{12} 512,這就可以爆搜寫嘍。
class Solution {
public:
    vector<int>job;
    int num[20],ans;//每個人的時間量
    int n;
    void dfs(int now,int k) {
        if(now == n) {
            int tmp = 0;
            for(int i = 0;i < k;i++) {
                tmp = max(tmp,num[i]);
            }
            ans = min(ans,tmp);
            return;
        }
        for(int i = 0;i < k;i++) {
            if(num[i] + job[now] < ans) {
                num[i] += job[now];
                dfs(now + 1,k);
                num[i] -= job[now];
            }
        }
    }
    int minimumTimeRequired(vector<int>& jobs, int k) {
        n = jobs.size();
        sort(jobs.begin(),jobs.end());
        memset(num,0,sizeof(num));
        job = jobs;
        ans = 1e9;
        if(k >= (n + 1) / 2) {
            for(int i = 0;i < k;i++) {
                num[i] += jobs[i + n - k];
            }
            n -= k;
        }
        
        dfs(0,k);
        return ans;
    }
};