LeetCode Weekly Contest 46解题思路

LeetCode Weekly Contest 46解题思路

详细代码可以fork下Github上leetcode项目,不定期更新。

赛题

本次周赛主要分为以下4道题:

Leetcode 661. Image Smoother

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:

  • The value in the given matrix is in the range of [0, 255].
  • The length and width of the given matrix are in the range of [1, 150].

直接求解法,很直观。

代码如下:

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

Leetcode 662. Maximum Width of Binary Tree

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

Leetcode 663. Equal Tree Partition

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

Leetcode 664. Strange Printer

Problem:

here is a strange printer with the following two special requirements:

  • The printer can only print a sequence of the same character each time.
  • At each turn, the printer can print new characters starting from and ending at any places, and will cover the original existing characters.

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可以用递归求解,那么问题就变成了,如何遍历所有可能的包裹方案。

用dp[i][j]表示在某个区间内的最小代价, 现在假设第i个位置的字符为a,那么在i和j的范围内,找寻下一个字符为a,记作下标为m,则可以将问题划分为:dp[i + 1][m - 1] 和 dp[m][j],代码如下:

    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];
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值