原題鏈接:https://leetcode.com/contest/weekly-contest-77
本週感覺難度不大….三道模擬,一道 DP。
Number of Lines To Write String
給定一個字符寬度數組 width[a..z],一個字符串 S。打印字符串,每行寬度限制爲100,不能截斷字符(換行)。
- 能打多少行
- 最後一行的打印寬度
模擬。
將 A 看成首尾相接循環串,每次以 A[i] 字符爲開頭,截取其中長度爲 A.length 的子串,與 B 進行對比,如果匹配則返回 True,直到所有子串都輪詢一遍仍沒有匹配的子串則返回 False。
// Time Complexity O(len(S)) class Solution { public int[] numberOfLines(int[] widths, String S) { char[] temp = S.toCharArray(); int line = 1, linew = 0; for (char c : temp) { int x = (int) (c - 'a'); if (linew + widths[x] > 100) { line++; linew = widths[x]; } else { linew += widths[x]; } } return new int[]{line, linew}; } }
Unique Morse Code Words
給定一個字符 -> Morse Code 映射 String[a..z],一個字符串數組 words[],將所有字符串翻譯成對應的 Morse Code 串,求不同串的數目。
模擬。
轉換字符串 -> insert in HashSet -> return HashSet.size()
// Time Complexity O(∑len(word)) class Solution { public int uniqueMorseRepresentations(String[] words) { String[] code = new String[]{".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."}; Set<String> set = new HashSet<>(); for (String word: words) { String res = trans(word, code); set.add(res); } return set.size(); } String trans(String word, String[] code) { StringBuilder res = new StringBuilder(); for (char c: word.toCharArray()) { res.append(code[c - 'a']); } return res.toString(); } }
Max Increase to Keep City Skyline
給定一個 grid[][]
矩陣,grid[i][j]
代表 (i,j) 建築物的高度,我們可以增加任意建築物的高度,但保持上下左右四個視圖與原建築矩陣相同,求所有建築物最多能增加多少高度(與原矩陣的高度差)。
Example:
Input: grid = [[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]]
Output: 35
Explanation:
The grid is:
[ [3, 0, 8, 4],
[2, 4, 5, 7],
[9, 2, 6, 3],
[0, 3, 1, 0] ]
gridNew = [ [8, 4, 8, 7],
[7, 4, 7, 7],
[9, 4, 8, 7],
[3, 3, 3, 3] ]
模擬。
求行列最大高度,
grid_new[i][j]
爲兩者取 min,這樣不會影響視圖且最優。// Time Complexity O(n^2) class Solution { public int maxIncreaseKeepingSkyline(int[][] grid) { int ans = 0; if (grid.length == 0 || grid[0].length == 0) return ans; int[] maxrow = new int[grid.length]; int[] maxcol = new int[grid[0].length]; for (int i = 0; i < grid.length; i++) { for (int j = 0; j < grid[0].length; j++) { maxrow[i] = Math.max(maxrow[i], grid[i][j]); maxcol[j] = Math.max(maxcol[j], grid[i][j]); } } for (int i = 0; i < grid.length; i++) { for (int j = 0; j < grid[0].length; j++) { ans += Math.min(maxrow[i], maxcol[j]) - grid[i][j]; } } return ans; } }
Split Array With Same Average
給一個 int 序列 A[],每個元素可以選擇放到兩個初始爲空的序列 B 或 C 中,全部元素都必須放到 B 或 C 中。能否找到一種分割策略,使 B 和 C 的平均值相同。
Example :
Input:
[1,2,3,4,5,6,7,8]
Output: true
Explanation: We can split the array into [1,4,5,8] and [2,3,6,7], and both of them have the average of 4.5.
Note:
- The length of
A
will be in the range [1, 30]. A[i]
will be in the range of[0, 10000]
.
DP
我一開始想到的是 dp,用 f[t][j] = true
代表子序列可以湊出 。已知 f[t][j]
的情況下,我們假設 A 可以分成兩個序列 B, C,長度爲 lb + lc = la
,那麼 B, C 滿足一些性質:
- 三個序列的平均值均相等。avg 是已知的,那麼 且 .
這就十分 nice,那麼我可以枚舉 ,通過 lb
可以求出 B, C, lc
,判斷 f[B][lb] && f[C][lc]
是否爲 True,如果是,那麼表示假設成立。
問題來了,B、C 是否不相交呢?注意,因爲可以有重複的元素存在,相交是指包含相同的元素而不是相同值的元素,[1,2,2,3] -> [1,2],[2,3]
不相交,而[1,2,2,3] -> [1,2,2],[2,3]
則相交。
假設 B、C 是相交的,相交子集爲 K。
那麼
以上證明,說明將子集 K 從 B 中剝離出去得到 B-K,其平均值也是 avg,那麼我們仍然可以得到兩個不相交的子序列。
那麼這個方法是可行的。
// Time Complexity O(n^2 * sum)
class Solution {
public boolean splitArraySameAverage(int[] A) {
if (A.length <= 1) return false;
int sum = 0;
for (int aA : A) sum += aA;
boolean[][] f = new boolean[sum+1][A.length+1];
f[0][0] = true;
for (int i = 0; i < A.length; i++) {
for (int t = sum; t >= A[i]; t--) {
for (int j = 1; j <= i+1; j++) {
f[t][j] = f[t][j] | f[t-A[i]][j-1];
}
}
}
for (int i = 1; i <= A.length / 2; i++) {
if (sum * i % A.length == 0) {
int b = sum * i / A.length;
if (f[b][i]) return true;
}
}
return false;
}
}