版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1434714
详细代码可以fork下Github上leetcode项目,不定期更新。
本次周赛主要分为以下4道题:
Problem:
Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoother to make the gray scale of each cell becomes the average gray scale (rounding down) of all the 8 surrounding cells and itself. If a cell has less than 8 surrounding cells, then use as many as you can.
Example 1:
Input: [1,1,1, 1,0,1, 1,1,1] Output: [0, 0, 0, 0, 0, 0, 0, 0, 0] Explanation: For the point (0,0), (0,2), (2,0), (2,2): floor(3/4) = floor(0.75) = 0 For the point (0,1), (1,0), (1,2), (2,1): floor(5/6) = floor(0.83333333) = 0 For the point (1,1): floor(8/9) = floor(0.88888889) = 0
Note:
直接求解法,很直观。
代码如下:
int[][] dir = {{1,0},{-1,0},{0,1},{0,-1},{0,0},{1,1},{-1,1},{-1,-1},{1,-1}};
public int[][] imageSmoother(int[][] M) {
int n = M.length;
int m = M[0].length;
int[][] ans = new int[n][m];
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
int sum = 0;
int cnt = 0;
for (int[] d : dir){
int nx = i + d[0];
int ny = j + d[1];
if (nx >= 0 && nx < n && ny >= 0 && ny < m){
cnt ++;
sum += M[nx][ny];
}
}
ans[i][j] = sum / cnt;
}
}
return ans;
}
Problem:
Given a binary tree, write a function to get the maximum width of the given tree. The width of a tree is the maximum width among all levels. The binary tree has the same structure as a full binary tree, but some nodes are null. The width of one level is defined as the length between the end-nodes (the leftmost and right most non-null nodes in the level, where the null nodes between the end-nodes are also counted into the length calculation.
经历了几个版本,其实只需要把每一层的坐标求出来,接着每层更新最小坐标和最大坐标即可,代码如下:
public int widthOfBinaryTree(TreeNode root) {
if (root == null) return 0;
map = new HashMap<>();
dfs(root, 0, 0);
int max = 0;
for (int key : map.keySet()){
Pair p = map.get(key);
max = Math.max(max, p.max - p.min + 1);
}
return max;
}
class Pair{
int min;
int max;
public Pair(){
this.min = Integer.MAX_VALUE;
this.max = Integer.MIN_VALUE;
}
}
Map<Integer, Pair> map;
public void dfs(TreeNode root, int layer, int pos){
if (root == null) return;
if (!map.containsKey(layer)) map.put(layer, new Pair());
Pair p = map.get(layer);
p.min = Math.min(p.min, pos);
p.max = Math.max(p.max, pos);
dfs(root.left, layer + 1, pos * 2);
dfs(root.right, layer + 1, pos * 2 + 1);
}
Problem:
Given a binary tree with n nodes, your task is to check if it’s possible to partition the tree to two trees which have the equal sum of values after removing exactly one edge on the original tree.
思路:求出sum,如果为奇数则不可能划分,否则找出sum / 2的子树。切割一条边,可以看作是该边所连结点下的子树和是否等于sum / 2,代码如下:
public boolean checkEqualTree(TreeNode root) {
if (root.left == null && root.right == null) return false;
list = new HashSet<>();
int sum = find(root);
if (sum % 2 != 0) return false;
int key = sum / 2;
return list.contains(key);
}
Set<Integer> list;
public int find(TreeNode root){
if (root == null) return 0;
int left = find(root.left);
int right = find(root.right);
list.add(left + right + root.val);
return left + right + root.val;
}
官方更新了最新的测试数据,上述代码bug了,具体bug样例为0,-1,1,关键在于sum = 0的情况,需要加个特判,代码如下:
public boolean checkEqualTree(TreeNode root) {
list = new HashMap<>();
int sum = find(root);
if (sum % 2 != 0) return false;
int key = sum / 2;
return (sum != 0 && list.containsKey(key)) || ( sum == 0 && list.get(sum) >= 2);
}
Map<Integer, Integer> list;
public int find(TreeNode root){
if (root == null) return 0;
int left = find(root.left);
int right = find(root.right);
int sum = left + right + root.val;
list.put(sum, list.getOrDefault(sum, 0) + 1);
return sum;
}
Problem:
here is a strange printer with the following two special requirements:
Given a string consists of lower English letters only, your job is to count the minimum number of turns the printer needed in order to print it.
Example 1:
Input: “aaabbb” Output: 2 Explanation: Print “aaa” first and then print “bbb”.
Example 2:
Input: “aba” Output: 2 Explanation: Print “aaa” first and then print “b” from the second place of the string, which will cover the existing character ‘a’.
思路:
就拿aba来说,最优路径是aaa -> b,所以对于打印机来说,打印单个a和多个a的代价是一样的,在考虑问题时,直接打印多个即可。那么接下来就要找出代价会变小的原因。
aabb
方案1: aaaa -> bb
方案2: aa —> bb
方案1与方案2等价
aaba
方案1: aaaa —> b
方案2: aa -> b -> a
方案1优于方案2
所以找到了优化准则:
对于被a包裹的子问题b可以用递归求解,那么问题就变成了,如何遍历所有可能的包裹方案。
用dpi表示在某个区间内的最小代价, 现在假设第i个位置的字符为a,那么在i和j的范围内,找寻下一个字符为a,记作下标为m,则可以将问题划分为:dpi + 1 和 dpm,代码如下:
int[][] dp = new int[101][101];
public int strangePrinter(String s) {
for (int i = 0; i < 101; ++i){
for (int j = 0; j < 101; ++j){
dp[i][j] = -1;
}
}
return f(s.toCharArray(), 0, s.length() - 1, dp);
}
public int f(char[] cs, int i, int j, int[][] dp){
if (i > j) return 0;
if (dp[i][j] > 0) return dp[i][j];
for (;i + 1 <= j && cs[i] == cs[i + 1]; ++i);
int res = 1 + f(cs, i + 1, j, dp);
for (int m = i + 1; m <= j; ++m){
if (cs[m] == cs[i]){
res = Math.min(res, f(cs, i + 1, m - 1, dp) + f(cs, m, j, dp));
}
}
return dp[i][j] = res;
}
迭代方案:
public int strangePrinter(String s) {
int[][] dp = new int[101][101];
int n = s.length();
if (n == 0) return 0;
char[] cs = s.toCharArray();
for (int i = 0; i < n; ++i) dp[i][i] = 1;
for (int i = n - 1; i >= 0; --i){
for (int j = i + 1; j < n; ++j){
dp[i][j] = dp[i + 1][j] + 1;
char c = cs[i];
for (int k = i; k < j; ++k){
if (cs[k + 1] == c) dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] - 1);
}
}
}
return dp[0][n - 1];
}