R a n k : 1179 / 4093 分 数 : 12 / 30 A C : 3 / 5 Rank :1179/4093 \quad分数:12/30 \quad AC:3/5 Rank:1179/4093分数:12/30AC:3/5
其实有9293人报名的…
看起来是个模拟,其实不用
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)
其实就是计算距离为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很小,其实时间复杂度和空间复杂度都很小,也就会很快。
暴力两重循环会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左右
一个比较难的题目…,让人欲罢不能?
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)的
首先,假设不存在多个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)
[1] 后序遍历 递归返回左右子树最优解和左右子树串行时间 通俗解释