Leetcode Weekly Contest 105

照例继续写比赛总结。
第一题比较简单,就是碰到是英文字母的情况下,就交换,左右2根指针,维护好。就好了。
https://leetcode.com/contest/weekly-contest-105/problems/reverse-only-letters/

public String reverseOnlyLetters(String S) {
        if (S.length() <= 1) return S;
        char[] cs = S.toCharArray();
        int i = 0, j = cs.length - 1;
        while (i < j) {
            while (i < j && !isLetter(cs[i])) i++;
            while (i < j && !isLetter(cs[j])) j--;
            if (i >= j) break;
            swap(cs, i, j);
            i++;
            j--;
        }
        return new String(cs);
    }

    boolean isLetter(char c) {
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
    }

    private void swap(char[] c, int i, int j) {
        char tmp = c[i];
        c[i] = c[j];
        c[j] = tmp;
    }

918. Maximum Sum Circular Subarray

https://leetcode.com/problems/maximum-sum-circular-subarray/description/

这道题如果不是循环数组,其实我们就是贪心,一旦遇到一个SUM <0,我们就可以把前面的都去掉。这样不断更新最大值。我们就可以找到全局最大的。这个贪心的思想的证明可以搜索一下,是一道很经典的题。
那么这题难点就在数组是循环的。也就是说除了是中间的区间,最大值很有可能是2端加起来的。
那么碰到循环数组的问题,无外乎三个套路。
拆分(HOUSE ROBBER那道,循环道路时用的是这个技巧)
倍增(就是在原数组后补到2倍长度,在2倍长数组的里处理,那么原本的N长的数组,我们可以变成N个新的长度为N的数组)
0->N-1, 1- >N, 2- >N+1 ..... N-1 -> 2*n-2
分别对每种循环的可能做处理,最后汇总得到解,这题可以运用这个策略,但是时间复杂度为N^2

取反(求最大,变成求最小)
在这道题里的运用,就是如果是2端加起来最大。那么必定我们需要在中间找一个最小。然后用SUM去减掉中间最小。就得到2端最大。

public int maxSubarraySumCircular(int[] A) {
        int l = A.length;
        int sum = 0;
        for(int i : A) sum+=i;
        int min = Integer.MAX_VALUE;
        int tot = 0;
        for(int i : A) {
            tot += i;
            min = Math.min(tot,min);
            if(tot > 0) tot = 0;
            
        }
        int tot2 = 0;
        int max = Integer.MIN_VALUE;
        for(int i : A) {
            tot2 += i;
            max = Math.max(tot2,max);
            if(tot2 < 0) tot2 = 0;
        }
        if(max < 0) return max;
        //System.out.println(max);
        return Math.max(max,sum-min);
    }

919. Complete Binary Tree Inserter

https://leetcode.com/problems/complete-binary-tree-inserter/
这道题,就是找到规律就好写了。比如一颗节点数为7的完全二叉树(自己画一下)下一个应该插的父亲节点是怎么算的。然后举例节点数为8,节点数为9.
找到那个就父亲节点的公式后。我们就需要一个LIST 维护住所有的父亲节点。然后可以O1 时间取出来。
父亲节点的公式是
(size +1)/2-1
做插入.

TreeNode rt;
    List res;
    public CBTInserter(TreeNode root) {
        rt = root;
        res = new ArrayList<>();
        assert(root != null);
        Queue qq = new LinkedList<>();
        qq.offer(root);
        while(!qq.isEmpty()){
            TreeNode cur = qq.poll();
            res.add(cur);
            if(cur.left == null) continue;
            qq.offer(cur.left);
            if(cur.right == null) continue;
            qq.offer(cur.right);
        }
        
    }
    
    public int insert(int v) {
        TreeNode par = res.get((res.size()+1)/2-1);
        TreeNode chd = new TreeNode(v);
        if(par.left != null){
            par.right = chd;
        }else{
            par.left = chd;
        }
        res.add(chd);
        return par.val;
    }
    
    public TreeNode get_root() {
        return rt;
    }

920. Number of Music Playlists

https://leetcode.com/problems/number-of-music-playlists/description/
这道题,我们思考,如果没有这个K的约束。我们要在L首歌里面确保能有N首歌。
我们不妨思考最后一步。在L-1首歌里有,N-1首歌。那么最后这首,一定是那首还没被选进去的歌。
当然也可能L-1首里,就已经有N首了。 那么最后这首,我们可以在N首里随便选了。

有了这个思路。
我们就可以定义状态方程。dp[i][j] 表示前I首选的歌里,用了J首不同的歌了。
转移方程就是
dp[i][j] = dp[i-1][j-1]*(n-(j-1)) + dp[i-1][j]*j
为什么要这样定状态。因为我们要确保L首里,一定N首歌每首都出现了。为了符合条件1. 所以J 这里就表示N首歌出现了几首,那么我们最后需要返回的就是DP L N
下面来思考怎么解决K的问题。
如果增加一首新的歌,是和前面肯定不会重复的,所以不用考虑K的问题。
关键增加一首老歌,我们必须要求,L-1~L-K 的K首歌里,不能选。
那么我们能选的不再是J首歌,是J-K 首了。
所以当J 《= K 的时候,是没办法选老歌的。因为必须K首得不一样。
修改转移方程为
dp[i][j] = dp[i-1][j-1]*(n-(j-1)) + dp[i-1][j]*Math.max(j-k,0)
为啥J-K首里可以随便选呢?
因为根据J首都是不同的歌,这J-K首一定不会和最后的K首歌 有交集。所以加进去是安全的。

int M = 1000000007;
    public int numMusicPlaylists(int N, int L, int K) {
        long[][] dp = new long[L+1][N+1];
        dp[0][0] = 1;
        for(int i = 1; i <= L; i++){
            for(int j = 1; j <= Math.min(i,N); j++){
                dp[i][j] = dp[i-1][j-1]*(N-j+1)%M;
                dp[i][j] = (dp[i][j]+dp[i-1][j]*Math.max(j-K,0))%M;
            }
        }
        return (int)dp[L][N];
    }

你可能感兴趣的:(Leetcode Weekly Contest 105)