【周赛总结】第204场周赛,组合数求解模板,栈解决正负数乘积

本文总结了2020年8月30日的第204场算法周赛,重点讨论了如何利用组合数性质解决1569. 将子数组重新排序得到BST问题,以及使用栈解决1567.乘积为正数的最长子数组问题。对于BST问题,通过确定根节点及其左右子树的特性,利用递归和组合数模板求解。而在处理乘积问题时,针对负数的奇偶性和0的出现,栈作为一种有效的数据结构被应用。
摘要由CSDN通过智能技术生成

2020/08/30第204场周赛

1569. 将子数组重新排序得到BST

在这里插入图片描述

这道题目首先需要找到关键点,再给定了根节点之后,第一个大于根节点和第一个小于根节点的数字必须是固定的,这决定了左右子树的根节点。因此我们知道,这个树除了根节点还具有n个字节点,其中,大于根节点的也就是右子树有m个点,因此我们可以选取 C n m C_n^m Cnm个位置放置,剩下的位置自然就是左子树。然后左右子树都还存在自身的排列,因此可以递归的求解。

注意这里求解组合数的方法利用了组合数的性质: C n m = C n − 1 m + C n − 1 m − 1 C_n^m = C_{n-1}^{m}+C_{n-1}^{m-1} Cnm=Cn1m+Cn1m1。因此可以用dp的思想比较快速的求解。

这里其实可以作为一个模板:

    private void helper(int n){
        for (int i = 0; i<=n;i++){
            for (int j = 0; j<=i;j++){
                if (j == 0) C[i][j] = 1;
                else C[i][j] = (int)((long)(C[i-1][j]+C[i-1][j-1])%mod);
            }
        }
    }

题解:

class Solution {
    int[][] C;
    int mod = 1000000007;
    public int numOfWays(int[] nums) {
        int n = nums.length;
        C = new int[n+2][n+2];
        helper(n);
        List<Integer> ans = new ArrayList<>();
        for (int num:nums) ans.add(num);
        return f(ans)-1;     
    }

    private int f(List<Integer> list){
        if (list.isEmpty()) return 1;
        int n = list.size();
        int bar = list.get(0);
        List<Integer> left = new ArrayList<>();
        List<Integer> right = new ArrayList<>();
        for (int i = 1; i<n;i++){ // 这里需要抛出根节点
            if (list.get(i)>bar) right.add(list.get(i));
            else left.add(list.get(i));
        }
        // 这里要小心翼翼,防止爆int
        return (int)((long)C[n-1][left.size()]*f(left)%mod * f(right)%mod);
    }


    // 递推的方法求解组合数
    private void helper(int n){
        for (int i = 0; i<=n;i++){
            for (int j = 0; j<=i;j++){
                if (j == 0) C[i][j] = 1;
                else C[i][j] = (int)((long)(C[i-1][j]+C[i-1][j-1])%mod);
            }
        }
    }
}

1567.乘积为正数的最长子数组

在这里插入图片描述

分析清楚题目可能的情况,三个情况:1. 偶数个负数;2.奇数个负数,因此我们需要保存第一个负数的位置,这个位置之后的区间是偶数个负数;3.出现0,全部清零,前面的都无效。

对于需要保存第一个负数位置的,采用栈的方法比较好。

class Solution {
    public int getMaxLen(int[] nums) {
        // 双指针,正数的情况,负数为偶数个,且无00
        int ans = 0;
        int n = nums.length;
        int num = 0,pre = -1;
        List<Integer> stack = new ArrayList<>();
        for (int i = 0; i<n ;i++){
            if (nums[i]<0) {
               num++; 
               stack.add(i);
            }
            else if (nums[i] == 0){
                num = 0;
                pre = i;
                stack.clear();
            }
            if (num%2 == 0) ans = Math.max(ans, i-pre);
            else ans = Math.max(ans, i-stack.get(0));
        }
        return ans;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值