周赛299——T2,T3题解

111 阅读2分钟

t2:2320. 统计放置房子的方式数 - 力扣(LeetCode)

分析题目,发现街道的两边是没有互相影响的,所以只要求出街道一边的放置方案数n,然后答案就是n2n^2

那怎么求一边的方案数呢?

一开始我用的是dfs,看能不能运气好过了。答案当然是喜提一个"超时"

于是开始思考:明显dfs是不行的,那只能从O(n)时间复杂度的方向想了,一般来说常见思路就是:从已知的结果中推出未知的结果,其实就是“动态规划”的思想。假设知道f(n-1)表示n-1的方案数,那么如何求出f(n)呢???

很明显有两种情况需要讨论【先固定最后的n,类似于背包问题】:

  1. 如果第n个位置有房子,那么第n-1个位置就不能放房子,此时f(n)=f(n-2)
  2. 如果第n个位置没有房子,那么第n-1个位置可以选择放或者不放房子,此时f(n)=f(n-1)

因此f(n) = f(n-1) + f(n-2),就是个斐波拉契数列。

另外要注意下乘法要用long来接。本人比赛提交的代码:

class Solution {
    private int mod = 1000000007;

    public int countHousePlacements(int n) {
        int[] f = new int[10001];
        f[1] = 2;
        f[2] = 3;

        for (int i = 3; i <= n; i++) {
            f[i] = (f[i - 1] % mod + f[i - 2] % mod) % mod;
        }

        long mod_ = (int)((f[n]) % mod);
        long tmpR = mod_  * mod_;
        int result = (int)(tmpR % mod);
        return result;
    }
}

t3: 2321. 拼接数组的最大分数 - 力扣(LeetCode)

假设数组1的和为sum1sum_1,数组2的和为sum2sum_2,数组1,2分别叫X,,Y

并且交换的最大分数对应的下标范围是i~j,于是交换后数组1的和表达式为:sum1=sum1(Xi+Xi+1+Xi+1+...Xj)+(Yi+Yi+1+Yi+1+...Yj){sum_1}^{'}=sum_1 - (X_i + X_{i+1}+X_{i+1}+...X_{j}) + (Y_i + Y_{i+1}+Y_{i+1}+...Y_{j}),

同理,交换后的数组2的和表达式为:sum2=sum2+(Xi+Xi+1+Xi+1+...Xj)(Yi+Yi+1+Yi+1+...Yj){sum_2}^{'}=sum_2 + (X_i + X_{i+1}+X_{i+1}+...X_{j}) - (Y_i + Y_{i+1}+Y_{i+1}+...Y_{j})

于是最终的结果就是max(sum1,sum2)max({sum_1}^{'}, {sum_2}^{'})

因为sum1sum_1是常数,所以问题变为求解:max((Xi+Xi+1+Xi+1+...Xj)+(Yi+Yi+1+Yi+1+...Yj)),或max((Xi+Xi+1+Xi+1+...Xj)(Yi+Yi+1+Yi+1+...Yj))max(- (X_i + X_{i+1}+X_{i+1}+...X_{j}) + (Y_i + Y_{i+1}+Y_{i+1}+...Y_{j})),或max((X_i + X_{i+1}+X_{i+1}+...X_{j}) - (Y_i + Y_{i+1}+Y_{i+1}+...Y_{j}))

观察到这里的XiXjX_i到X_jYiYjY_i到Y_j对应着同一段范围,上述两式可转变为:max((YiXi)+(Yi+1Xi+1)+....(YjXj)))max( (Y_i-X_i) + (Y_{i+1}-X_{i+1}) + ....(Y_{j}-X_{j})))max((XiYi)+(Xi+1Yi+1)+....(XjYj)))max( (X_i-Y_i) + (X_{i+1}-Y_{i+1}) + ....(X_{j}-Y_{j})))

于是可以将数组YY减去数组XX,得到数组Z=Y0X0Y1X1,....Yn1Xn1Z={Y_0-X_0,Y_{1}-X_{1},....Y_{n-1}-X_{n-1}}

所以只要求出ZZ的最大连续子数组和就行

同理,可以将数组XX减去数组YY,得到数组Z=X0Y0X1Y1,....Xn1Yn1Z={X_0-Y_0,X_{1}-Y_{1},....X_{n-1}-Y_{n-1}}

所以只要求出ZZ的最大连续子数组和就行

比赛时通过的代码:

补充下求最大子数组用一个变量就行

  public int maximumsSplicedArray(int[] nums1, int[] nums2) {
        int n = nums1.length;
        int[] Y_X = new int[n];
        int[] X_Y = new int[n];
        int sum1 = 0, sum2 = 0;
        for (int i = 0; i < n; i++) {
            sum1 += nums1[i];
            sum2 += nums2[i];
            Y_X[i] = nums2[i] - nums1[i];
            X_Y[i] = nums1[i] - nums2[i];
        }
        
        int maxY_X = Y_X[0];
        int maxX_Y = X_Y[0];
        
        int[] dY_X = new int[n];
        int[] dX_Y = new int[n];
        dY_X[0] = Y_X[0];
        dX_Y[0] = X_Y[0];
        for (int i = 1; i < n; i++) {
            if (dY_X[i - 1] < 0) {
                dY_X[i] = Y_X[i];
            } else {
                dY_X[i] = Y_X[i] + dY_X[i - 1];
            }
            maxY_X = Math.max(maxY_X, dY_X[i]);
            
            if (dX_Y[i - 1] < 0) {
                dX_Y[i] = X_Y[i];
            } else {
                dX_Y[i] = X_Y[i] + dX_Y[i - 1];
            }
            maxX_Y = Math.max(maxX_Y, dX_Y[i]);
        }
        
        int maxSum1 = sum1 + maxY_X;
        int maxSum2 = sum2 + maxX_Y;
        return Math.max(maxSum1, maxSum2);
    }