LeetCode 115th Weekly Contest 总结

总体来说,这周题目比较难。以后还是每周都来总结下周赛。

1. 957. Prison Cells After N Days

题意

类似于细胞生命的游戏,每天细胞会根据前一天的状态进行演变,演变规则:

Each day, whether the cell is occupied or vacant changes according to the
following rules:
If a cell has two adjacent neighbors that are both occupied or both vacant,
then the cell becomes occupied.
Otherwise, it becomes vacant.

思路

开始比较直接的做法就是遍历n天,再遍历n个细胞:

public int[] prisonAfterNDays(int[] cells, int N) {
        while (N > 0) {
            N--;
            int[] cells2 = new int[8];
            for (int i = 1; i < 7; ++i)
                cells2[i] = cells[i - 1] == cells[i + 1] ? 1 : 0;
            cells = cells2;
        }
        return cells;
}

但是这个解答在N很大时超时,于是必须考虑优化方案了。

  • 我们来思考一下,这个状态中可能出现重复的吗?也就是如果存在循环,就会好办很多,我们就可以取周期的余,就到了跳过一次循环后的状态了;其实一共8个细胞,出去首尾两个状态始终是0,其余6个组成的状态数一共是2^6=64种,所以变化那么多天,肯定是存在循环的(其实就是也可以猜测如果没有循环这题就没法解了= =)
  • 下一步,怎么判断出现过的状态呢?并且还需要知道是在之前哪天出现的,因为今天减去上一期相同状态出现的那天,就等于循环的周期啦。自然而然想到应该用hash table存储。
  • 还需要注意的点就是,hash table中的key的存储,应该是用字符串化后的数组,不然hash table判断的时候用的是数组的reference,每次都不会一样.

代码:

class Solution {
    public int[] prisonAfterNDays(int[] cells, int N) {
        int[] tmp = new int[8];
        Map<String, Integer> map = new HashMap<>();
        while (N > 0) {
            map.put(Arrays.toString(cells), N);
            N--;
            for (int i = 1; i < 7; i++) {
                tmp[i] = cells[i - 1] == cells[i + 1] ? 1 : 0;
            }
            for (int i = 0; i < 8; i++) cells[i] = tmp[i];
            if (map.containsKey(Arrays.toString(cells))) {
                int T = map.get(Arrays.toString(cells)) - N;  //周期
                N %= T;
            }
        }
        return cells;
    }
}

总结:

这种状态转换,且n还很大,一般就是需要找循环,然后取余mod,来减少循环长度。
这样的就遍历数组,再加上一个优化步骤的题目,面试也会将常考

2. 958. Check Completeness of a Binary Tree

题意

判断一棵树是否是完全二叉树

思路

根据完全二叉树的性质,最下层节点应该都在左边;

  • 可以考虑下层序遍历,如果是完全二叉树的话,那么当遇到空节点的时候,中后就不应该再遇到空节点了。
  • 层序遍历,无论是否为空节点都add进队列,当队列头是空节点时,说明遇到第一个空节点了;然后再判断队列中剩下的节点,如果有非空的,则不是完全二叉树

代码:

class Solution {
    public boolean isCompleteTree(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (queue.peek() != null) {
            TreeNode cur = queue.poll();
            queue.add(cur.left);
            queue.add(cur.right);
        }
        while (!queue.isEmpty() && queue.peek() == null) {
            queue.poll();
        }
        return queue.isEmpty();
    }
}

总结

树的层序遍历的扩展

3. 959. Regions Cut By Slashes

哈哈比赛时这题题目都没看懂 = =

题意

In a N x N grid composed of 1 x 1 squares, each 1 x 1 square consists of a /
, or blank space. These characters divide the square into contiguous
regions.

大概就是给一个字符串代表矩形的分割方式,求在矩形区域的个数。

思路

什么鬼题目??大脑一片空白?莫急,让我们慢慢分析一下。

  • 怎么才能判断这块区域是一块呢?这种图形题,又不可能考计算几何 = =,所以唯一可能就是通过染色的方法,我们可以标记对吧;
  • 那么怎么染色呢?是不是想到了并查集?就是将相连的区域都染为同一个颜色,最后颜色的树木不就是的区域的数目吗?
  • 有了基本的思路,方法是可行的,到了具体实现了;这里一个难想到的点就是,根据\\/这两个字符,去分割矩形小框框,怎么去分呢?这里需要把每个小矩形再分成四个小区域:如下图所示:
    这样,我们就可以根据当前是什么符号,去将不同的区域进行连接了

pig

代码:

class Solution {
    class UF {
        int[] parent;
        public UF(int n) {
            parent = new int[n];
            for (int i = 0; i < n; i++) parent[i] = i;
        } 
        public int  find(int x) {
            if (parent[x] != x) parent[x] = find(parent[x]);
            return parent[x];
        }
        public void union(int x, int y) {
            parent[find(x)] = find(y);
        }
    }
    
    int count = 0;
    UF uf;
    public int regionsBySlashes(String[] grid) {
        int n = grid.length;
        uf = new UF(n * n * 4);
        count = n * n * 4;
        //四个小区块:top: 0, right: 1, bottom: 2, left: 3
        for (int r = 0; r < n; r++) {
            for (int  c = 0; c < n; c++) {
                if (r > 0) {
                    check(changeIndex(n, r-1, c, 2), changeIndex(n, r, c, 0));
                }
                if (c > 0) {
                    check(changeIndex(n, r, c - 1, 1), changeIndex(n, r, c, 3));
                }
                if (grid[r].charAt(c) != '/') {
                    check(changeIndex(n, r, c, 3), changeIndex(n, r, c, 2));
                    check(changeIndex(n, r, c, 1), changeIndex(n, r, c, 0));
                }
                if (grid[r].charAt(c) != '\\') {
                    check(changeIndex(n, r, c, 0), changeIndex(n, r, c, 3));
                    check(changeIndex(n, r, c, 1), changeIndex(n, r, c, 2));
                }
            }
        }
        return count;
    }
    
    private int changeIndex(int n, int x, int y, int k) {
        return (x * n + y) * 4 + k;
    }
    
    private void check(int n1, int n2) {
        if (uf.find(n1) != uf.find(n2)) {
            uf.union(n1, n2);
            count--;
        }
    }
}

总结

并查集的考察越来多多了

4. 960. Delete Columns to Make Sorted III

题意

这题是之前几题的延续
删除某些列后,每行的元素都是按字母排序的

Suppose we chose a set of deletion indices D such that after deletions, the
final array has every element (row) in lexicographic order.

思路

  • 求每个字符串最少删掉的字符,使得每个字符串中的字符都是递增的;我们可以先考虑考虑1个字符串的情况:
    也就是说,比如"edcba",求它最少减少的字符,使得它自增,是不是觉得很熟悉呢?问题可以转化为最长递增子序列LIS,n - LIS
    即为所求了!回忆LIS的基本解法是:
for j : 0 -> n
  for i : 0 -> j
     if (A[i] < A[j]) dp[j] = max(dp[j], dp[i] + 1)
  • 想清楚了一个字符串的case,再来想想多个字符串怎么办?
    这里的一个思路就是 将每列看成一个元素,那么只要判断在每个case下,是不是每行元素都满足递增,如果满足,则更新dp;否则跳过;

代码:

class Solution {
    public int minDeletionSize(String[] A) {
        int m = A.length, n = A[0].length();
        int[] dp = new int[n];  //每列看成一个元素!
        int res = Integer.MAX_VALUE;
        Arrays.fill(dp, 1);
        for (int j = 0; j < n; j++) {
            for (int i = 0; i < j; i++) {
                boolean valid = true;
                //检查每个字符串是不是都满足
                for (int r = 0; r < m; r++) {
                    if (A[r].charAt(i) > A[r].charAt(j)) {
                        valid = false;
                        break;
                    }
                }
                if (valid) dp[j] = Math.max(dp[j], dp[i] + 1);
            }
            res = Math.min(res, n - dp[j]);
        }
        return res;
    }
}

总结

其实这题就是LIS的变种

总体来说,这次周赛除了第三题,其他都可以做出来的,其他的都比较常规,但是...emmm 加油吧

posted @ 2018-12-16 19:54  shawshawwan  阅读(233)  评论(0编辑  收藏  举报