2020 力扣杯!Code Your Future 春季全国编程大赛 题解

R a n k : 1179 / 4093 分 数 : 12 / 30 A C : 3 / 5 Rank :1179/4093 \quad分数:12/30 \quad AC:3/5 Rank:1179/409312/30AC:3/5
其实有9293人报名的…

LCP 06. 拿硬币

看起来是个模拟,其实不用

class Solution {
public:
    int minCount(vector<int>& coins) {
        int sum = 0;
        for(int e:coins){
            sum += (e+1)/2;
        }
        return sum;
    }
};

时间复杂度:O(n) ,空间复杂度:O(1)

LCP 07. 传递信息

其实就是计算距离为k的可达矩阵,下面是矩阵快速幂的做法

typedef long long ll;
const ll mod = 1e9+7;
struct node {
	ll mat[15][15];//定义矩阵 
}x,y;
int len;
node mul(node x,node y){//矩阵乘法 
	node tmp;
	for(int i=0;i<len;i++){
		for(int j=0;j<len;j++){
			tmp.mat [i][j]=0;
			for(int k=0;k<len;k++){
				tmp.mat [i][j]+=(x.mat [i][k]*y.mat [k][j])%mod;
			}
			tmp.mat [i][j]=tmp.mat[i][j]%mod;
		}
	}
	return tmp;
}
node matpow(node x,node y,int num){//矩阵快速幂 
	while(num){
		if(num&1){
			y=mul(y,x);
		}
		x=mul(x,x);
		num=num>>1;
	}
	return y;
}
class Solution {
public:
    int numWays(int n, vector<vector<int>>& relation, int k) {
        node x,res;
        len = n;
        memset(x.mat,0,sizeof(x.mat));
        for(auto& e:relation){
            x.mat[e[0]][e[1]] = 1;
        }
        res = matpow(x,x,k-1);
        return res.mat[0][n-1];
    }
};

时间复杂度: O ( n 3 l o g k ) O(n^3logk) O(n3logk) 空间复杂度:O(1)
这里的n很小,其实时间复杂度和空间复杂度都很小,也就会很快。

LCP 08. 剧情触发时间

暴力两重循环会TLE,使用二分来做,二分写的漏洞百出…还是不太熟啊…
思路是维护一个C,R,H三个前缀数组,然而二分搜索requirements的每个元素,找到满足的最小天数。

int c[10010],r[10010],h[10010];
class Solution {
public:
    vector<int> getTriggerTime(vector<vector<int>>& increase, vector<vector<int>>& require) {
        int len = require.size(),n = increase.size();
        vector<int> res(len,-1),day(3,0);
        for(int i=1;i<=n;i++){
            c[i] = c[i-1]+increase[i-1][0];
            r[i] = r[i-1]+increase[i-1][1];
            h[i] = h[i-1]+increase[i-1][2];
        }
        for(int i=0;i<len;i++){
            int left = 0,right = n;
            while(left<right){
                int mid = (left+right)/2;
                if(c[mid]>=require[i][0]&&r[mid]>=require[i][1]&&h[mid]>=require[i][2]){
                    right = mid;
                }
                else left = mid+1;
            }
            if(c[left]>=require[i][0]&&r[left]>=require[i][1]&&h[left]>=require[i][2]){
                res[i] = left;
            }
            else res[i] = -1;            
        }
        return res;
    }
};

时间复杂度: O ( k l o g n ) O(klogn) O(klogn),空间复杂度:O(n+k)
n为increase.length,k=requirements.length
计算次数大概在 1 0 5 10^5 105左右

LCP 09. 最小跳跃次数(hard)

一个比较难的题目…,让人欲罢不能?
dp[i]表示从i跳出需要的最小的按压弹簧的次数
需要逆序遍历,因为前面的需要用到后面的状态。

class Solution {
public:
    int minJump(vector<int>& jump) {
        int m = jump.size();
        int dp[m];
        for(int i=m-1;i>=0;i--){
        	// 如果能直接跳出去,则次数等于1
            if(i+jump[i]>=m) dp[i] = 1;
            // 否则,就等于像右跳能跳出的位置所需的按压次数+1
            else dp[i] = dp[i+jump[i]]+1;
            // 假如是向左跳,假如向向左跳,然后向右跳,可以使用更少的次数的话,则可以更新
            for(int j=i+1;j<m&&j<i+jump[i]&&dp[j]>=dp[i]+1;j++){
                dp[j] = dp[i]+1;
            }
        }
        return dp[0];
    }
};

时间复杂度:O(n) 加了剪枝,可以认为是O(n)的

LCP 10. 二叉树任务调度

首先,假设不存在多个cpu的情况(即只有一个cpu),要执行完所有的前置任务,那前置任务的总时间肯定是preTime = sum(node.left) + sum(node.right)preTime=sum(node.left)+sum(node.right)。这时,我们将preTime看成一个整体。
那么现在变成双核CPU了。一个整体的preTime开始双核并行了,那么一个整体下的preTime是多少呢?
很显然,是preTime/2
是不是豁然开朗了?在前置任务最为理想的情况下,所有任务都能一直并行,不存在串行时间。这个类似于动态规划的前置条件。至于前置任务再往前的任务,和任务它到底是怎么分配时间的,怎么去分摊时间,我们并不关心,总之,你能在preTime/2的时间内完成,就OK了。如果CPU核心更多,就是preTime/n。
当然,前置任务最优的解preTime/2,是一个理想情况,具体的任务执行,是非常有可能达不到这种情况。比如题目的测试用例1。
所以,每个节点的任务执行时间的最小值,应该是Max(time(node.left),time(node.right),preTime/2) + node.valMax(time(node.left),time(node.right),preTime/2)+node.val。
即左子树执行完成的最小时间、右子树执行完成的最小时间、左右子树全部节点并行执行的时间,三者的最大值,再加上当前节点的任务时间。
最后将最优时间往根节点递推。抵达根节点后的最优解,就是全局的最优解 [ 1 ] ^{[1]} [1]

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    pair<double,double> dfs(TreeNode* root){
        if(root==NULL) return make_pair(0,0);
        pair<int,double> ltime = dfs(root->left), rtime = dfs(root->right);
        double mint = max(max(ltime.second,rtime.second),(ltime.first+rtime.first)/2.0) + root->val;
        return make_pair(ltime.first+rtime.first+root->val,mint);
    }
    double minimalExecTime(TreeNode* root) {
        return dfs(root).second;
    }
};

时间复杂度:O(n)

Ref

[1] 后序遍历 递归返回左右子树最优解和左右子树串行时间 通俗解释

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值