No.1 解碼異或後的數組數組
解題思路函數
a ^ b = c
則有 a ^ b ^ a = c ^ a
即 b = a ^ c
優化
代碼展現ui
class Solution { public int[] decode(int[] encoded, int first) { int[] res = new int[encoded.length + 1]; res[0] = first; for (int i = 0; i < encoded.length; i++) { // res[i] ^ res[i+1] = encoded[i] res[i + 1] = encoded[i] ^ res[i]; } return res; } }
No.2交換鏈表中的節點code
解題思路get
比較樸素的實現,封裝了一個函數,遍歷三次鏈表。it
代碼展現io
class Solution { public ListNode swapNodes(ListNode head, int k) { int n = 0; for (ListNode cur = head; cur != null; cur = cur.next) { n++; } ListNode a = getKthNode(head, k); ListNode b = getKthNode(head, n - k + 1); int tmp = a.val; a.val = b.val; b.val = tmp; return head; } ListNode getKthNode(ListNode head, int k) { ListNode cur = head; for (int i = 0; cur != null; i++, cur = cur.next) { if (i == k - 1) { return cur; } } return null; } }
No.3執行交換操做後的最小漢明距離class
解題思路stream
使用並查集維護集合 —— 一個位置的數字與其餘哪些位置的數字可交換。
而後貪心法計數便可。
代碼展現
class UnionFind { public UnionFind(int size) { f = new int[size]; Arrays.fill(f, -1); } public int find(int x) { if (f[x] < 0) return x; return f[x] = find(f[x]); } public boolean merge(int a, int b) { int fa = find(a); int fb = find(b); if (fa == fb) return false; f[fa] = fb; return true; } private int[] f; } class Solution { public int minimumHammingDistance(int[] source, int[] target, int[][] allowedSwaps) { UnionFind uf = new UnionFind(source.length); for (int[] a : allowedSwaps) { uf.merge(a[0], a[1]); } // map[i] 是一個 counter // map[i][j] > 0 表示 source[i] 能夠經過交換變成 j // 使用 map<int,map> 而不是 map<int,set> 的緣由是避免 source 有重複數字 Map<Integer, Map<Integer, Integer>> map = new HashMap<>(); for (int i = 0; i < source.length; i++) { int fi = uf.find(i); if (!map.containsKey(fi)) { map.put(fi, new HashMap<>()); } Map<Integer, Integer> cnt = map.get(fi); cnt.put(source[i], cnt.getOrDefault(source[i], 0) + 1); map.put(i, cnt); } int res = target.length; for (int i = 0; i < target.length; i++) { Map<Integer, Integer> cnt = map.get(i); if (cnt.getOrDefault(target[i], 0) > 0) { res--; cnt.put(target[i], cnt.get(target[i]) - 1); } } return res; } }
No.4完成全部工做的最短期
解題思路
二分 + 枚舉
代碼展現
class Solution { public int minimumTimeRequired(int[] jobs, int k) { // 使用 long 以免 (l + r) 溢出 long l = Arrays.stream(jobs).min().getAsInt(); long r = Arrays.stream(jobs).sum(); while (l + 1 < r) { long mid = (l + r) / 2; if (check(jobs, k, mid)) { r = mid; } else { l = mid; } } return (int) (check(jobs, k, l) ? l : r); } boolean check(int[] jobs, int k, long limit) { // 判斷 k 個工人可否在 limit 的時限下完成任務 return dfs(jobs, 0, new int[k], limit); } // 枚舉每一個任務分配給哪一個工人 // sum[i] 表示當前 i 工人獲得的任務的總工時 boolean dfs(int[] jobs, int curJob, int[] sum, long limit) { if (curJob == jobs.length) { return true; } for (int i = 0; i < sum.length; i++) { if (sum[i] + jobs[curJob] <= limit) { sum[i] += jobs[curJob]; if (dfs(jobs, curJob + 1, sum, limit)) { return true; } sum[i] -= jobs[curJob]; // 一個很重要的優化 // sum[i] = 0 表示 curJob 被分給一個新的工人 // 若是未能在上方 return true, 換一個新工人也不可能達標 if (sum[i] == 0) { break; } } } return false; } }