题解 | #填充数组#

填充数组

http://www.nowcoder.com/practice/3e34d9ed0bbc4db68b6fbca20a62926d

题意理解

给我们一个数组a,由自然数组成,以及一个最大值k。我们要把所有的0换成1~k中的某个值(可以重复),保持数组是递增的(这里的递增不是单调的)。问一共有多少种方法。

方法一

暴力枚举(会超时)
最简单且容易想到的方法就是列举出数组所有可能的取值,再判断是否满足递增,如果满足,种数加1。这里使用深度优先搜索,当前位置为0时,枚举所有可能的取值并递归;当前位置非0时跳过。边界条件为递归到最后一位且满足题目要求,此时种数加1。注意在递归时要判断是否满足a[i1]<=a[i]a[i-1]<=a[i]

具体代码如下:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param a int整型vector 
     * @param k int整型 
     * @return int整型
     */

    int dfs(vector<int>& a, int k, int index)
    {
        if (index==a.size()) return 1;
        int ans = 0;
        //处理当前位置为0的情况
        if (!a[index])
        {
            //注意可能的取值范围
            int begin = 1;
            if (index) begin = a[index-1];
            for (int i=begin;i<=k;i++)
            {
                a[index] = i;
                ans = (ans + dfs(a,k,index+1))%1000000007;
                a[index] = 0;
            }
        }
        else
        {
            //判断是否满足递增
            if ((index) && a[index-1]>a[index]) return 0;
            else return dfs(a,k,index+1);
        }
        return ans;
    }
    
    int FillArray(vector<int>& a, int k) {
        // write code here
        return dfs(a,k,0);
    }
};

时间复杂度: O(kN)O(k^N)。每一位有k种可能,一共有N位。
空间复杂度: O(N)O(N)。递归的深度不会超过数组的长度N。

方法二

动态规划
输入的数组已经满足了:除0以外的值都是递增的。我们将数组a视为被非0的数分隔为若干段,每段为连续的1个或多个0。可以发现,每一段的取值之间是互不干扰的。因此,最终的种数为每一段的种数的乘积。而且计算种数的时候,可以不考虑数值的具体大小,一律使用从1到m,m为这一段0的个数。

对于每一段,我们要做的是用i个数填满j个位置,且满足数组递增,用dp[j][i]。填j个位置,可以考虑先把最后一位填b,那么就是用1~b填j-1位。那么状态转移方程为:
dp[j][i]=b=1idp[j1][b]=dp[j1][i]+dp[j][i1]dp[j][i]=\sum_{b=1}^i dp[j-1][b] = dp[j-1][i] + dp[j][i-1]

边界的话,dp[1][i]=idp[1][i] = i;dp[j][1]=1dp[j][1] = 1

dp的示意图如下: alt

具体代码如下:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param a int整型vector 
     * @param k int整型 
     * @return int整型
     */
    int dp[1001][1001];
    void GetSortNumber(int x,int y)
    {
        dp[1][1] = 1;
        for (int i=1;i<=x;i++) dp[1][i] = i;
        for (int i=1;i<=y;i++) dp[i][1] = 1;
        for (int i=2;i<=y;i++)
        {
            for (int j=2;j<=x;j++)
            {
                dp[i][j] = (dp[i-1][j] + dp[i][j-1]) % 1000000007;
            }
        }
    }
    
    int FillArray(vector<int>& a, int k) {
        // write code here
        vector<int> s;
        //把所有dp求好,后面直接调用
        GetSortNumber(k,a.size());
        for (int i=0;i<a.size();i++)
        {
            if (a[i]==0)
            {
                int minm,maxm,count=1;
                if (i==0) minm = 1;
                else minm = a[i-1];
                while ((i+1)<a.size() && a[i+1]==0)
                {
                    count++;
                    i++;
                }
                if ((i+1)==a.size())  maxm = k;
                else maxm = a[i+1];
                //计算可以取值的范围(个数)
                int num = maxm - minm + 1;
                s.push_back(dp[count][num]);
            }
        }
        int ans = 1;
        for (int i=0;i<s.size();i++)
            ans = ((long long)ans * s[i]) % 1000000007;
        return ans;
    }
};

时间复杂度: O(Nk)O(Nk)。求解dp数组是用到了双重循环,每层分别为数组a长度N和最大值k。
空间复杂度: O(Nk)O(Nk)。dp数组的长为k,宽为N。

全部评论

相关推荐

03-13 00:04
已编辑
吉林大学 Java
约面的挺突然。。狠下心接了1.自我介绍2.讲讲JAVA的反射3.可以继续讲讲AOP,动态代理[&nbsp;因为讲反射不小心吟唱到了例如AOP的动态代理,但是这块记忆的非常不熟,结果磕磕绊绊&nbsp;]4.项目我看你写了AOP和注解,具体怎么实现滑动窗口限流的[&nbsp;梦到什么说什么,吟唱八股发散千万不要散到自己不熟悉的区域&nbsp;]5.也讲讲为什么另一个项目选择令牌桶,具体流程6.&nbsp;OK,讲讲&nbsp;Redis&nbsp;的数据类型?还有吗?就了解这五种嘛[&nbsp;把5个的基础类型从应用对比到历届底层全都吟唱了一遍。一句还有吗直接没力气了,简历就写了理解5种,别的我是真一点没看TT&nbsp;]7.讲讲Redission分布式锁实现8.这个指数退避怎么实现的9.在这里有考虑去保障幂等性嘛10.这里为什么使用指数退避呢?&nbsp;什么时候用均匀重传[已经晕过去了说不了解,刚说了后就意识到,估计应该说指数退避能缓解压力防止下游服务器雪崩之类的]11.ok,那讲讲JMM12.讲讲RocketMQ如何保证的不丢消息13.讲讲RocketMQ延迟消息原理14.讲讲项目Redis实现会话记忆这一块15.如果ai调用function&nbsp;calling出现幻觉,有考虑怎么解决吗?[&nbsp;不了解,面试官说什么接口幂等化,高危操作人工防护,没在听,感觉人已经飞升了TT&nbsp;]16.mcp了解嘛?和function&nbsp;calling有什么区别[&nbsp;依旧不了解,只能说了个前者规范架构抽象解耦,后者耦合高只能算个工具调用]17.AI生成代码的代码质量怎么保障,那平时如何review的呢18.算法。lc215&nbsp;&nbsp;数组中最大第k个元素19.打算考研还是本科就业20.反问1️⃣有哪里不足,有哪些需要提高的部分。[主要说知识广度不够,多刷算法,让我别太紧张]2️⃣部门业务会做什么人生第二次面试。感觉大厂面试官的气场压力很大应该凉了不过这次面试非常锻炼心态,多面试,多面试。
冰炸橙汁_不做oj版:redis除了五种基本数据类型,其他的几种还是要掌握一下的,挺常用
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务