这一周的题都比较简单,感觉并没有每天写个blog的必要,于是合到一起写一个周总结。
根据给出的老人信息字符串解析出年龄严格大于60岁的老人。
题目链接
纯字符串模拟,可完全忽略。
给定 n n n枚含 k k k个面的骰子,返回所有能得到点数和为 t a r g e t target target的总方案数。
题目链接
范围不大,一道简单的动态规划题。转移方程如下:
d p [ n ] [ i ] = d p [ n ] [ i ] + d p [ n − 1 ] [ i − j ] dp[n][i] = dp[n][i] + dp[n-1][i-j] dp[n][i]=dp[n][i]+dp[n−1][i−j],其中 1 ≤ j ≤ k 1\le j\le k 1≤j≤k。
注意初始化处理,另外方案数过大要处理。
class Solution {
public:
const int mod = 1000000007;
int numRollsToTarget(int n, int k, int target) {
long long dp[31][1001];
memset(dp, 0, sizeof(dp));
for(int i=1;i<=k;i++) dp[1][i]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=target;j++){
for(int p=1;p<=k;p++)
if(j-p>0) dp[i][j] = (dp[i][j] + dp[i-1][j-p])%mod;
}
//for(int i=1;i<=n;i++)
// for(int j=1;j<=target;j++) cout << dp[i][j] << " ";
return dp[n][target];
}
};
给定一个整数 n n n,求在这个数(的平方)范围内所有是一个数的平方且可以分割成连续数且这些数的和即为该数本身的数的和。
题目链接
这道题对应的数组可以直接前往OEIS上扒下来,简单打表快速通过(
如果不这么做,也可以对范围内的每个平方数做简单的记忆化验证。
用递归的方式,不断取一个数的后半部分,将后半部分代表的数从需要表示的结果值中除去,剩下的部分继续交给递归,具体细节见代码。
inline bool check(int t, int x) {
if (t == x) return true;
int d = 10;
while (t >= d && t % d <= x) {
if (check(t / d, x - (t % d))) return true;
d *= 10;
}//不断增长切割长度,将数分成两段,递归后则是分成多段
return false;
}
int f[1010];
int _ = []() {
for (int i = 1; i < 1010; i++) {
f[i] = f[i - 1];
if (check(i * i, i)) f[i] += i * i;
}
return 0;
}();//这是一个C++的初始化函数,还蛮耍赖的(
class Solution {
public:
int punishmentNumber(int n) {
return f[n];
}
};
//ref:宫水三叶
给你一个整数 n u m num num ,返回 n u m num num 中能整除 n u m num num 的数位的数目。
题目链接
转成string后提取数位,模拟即可,题解略。
给出一块长为 h h h,宽为 w w w的蛋糕,以及一系列蛋糕在横向与竖向上的切割点,求切割后最大的一块蛋糕的面积。
题目链接
将切割点排序并加入0和总长度两个点,在长宽上都找出最长的分割线,相乘得到的结果就是最大块的蛋糕。
class Solution {
public:
int maxArea(int h, int w, vector<int>& horizontalCuts, vector<int>& verticalCuts) {
int maxlen = 0, maxweight = 0;
int n = horizontalCuts.size(), m = verticalCuts.size();
sort(horizontalCuts.begin(), horizontalCuts.end());
sort(verticalCuts.begin(), verticalCuts.end());
for(int i=0;i<n;i++){
if(i == 0) maxlen = max(maxlen, horizontalCuts[i] - 0);
else maxlen = max(maxlen, horizontalCuts[i] - horizontalCuts[i-1]);
}
maxlen = max(maxlen, h-horizontalCuts[n-1]);
for(int i=0;i<m;i++){
if(i == 0) maxweight = max(maxweight, verticalCuts[i] - 0);
else maxweight = max(maxweight, verticalCuts[i] - verticalCuts[i-1]);
}
maxweight = max(maxweight, w-verticalCuts[m-1]);
long long sum = (1ll*maxlen*maxweight)%1000000007;
return (int)sum;
}
};
给你一个整数数组 gifts ,表示各堆礼物的数量。每一秒,你需要执行以下操作,返回在 k 秒后剩下的礼物数量:
- 选择礼物数量最多的那一堆。
- 如果不止一堆都符合礼物数量最多,从中选择任一堆即可。
- 选中的那一堆留下平方根数量的礼物(向下取整),取走其他的礼物。
题目链接
最大堆模拟即可,题解略。这题是不是在哪里做过啊(笑)
给你一个整数数组 c i t a t i o n s citations citations,其中 c i t a t i o n s [ i ] citations[i] citations[i]表示研究者的第 i i i篇论文被引用的次数。计算并返回该研究者的h指数。
一名科研人员的h指数是指他(她)至少发表了h篇论文,并且每篇论文至少被引用h次。
题目链接
本题比较灵活。
一种显然的思路是,对 c i t a t i o n s citations citations从大到小排序,之后遍历,在第i个位置,若该位置的值大于等于该位置及该位置之后所有文章的总数,则得到目前序列最大的h指数,为该位置及该位置之后所有文章的总数。
另一种思路也很简单,二分法尝试从 0 → c i t a t i o n s . s i z e ( ) 0 \to citations.size() 0→citations.size()枚举可能的h指数,并使用验证函数验证即可。
第三种思路则是计数统计,已知h指数的范围有且仅有 0 → c i t a t i o n s . s i z e ( ) 0 \to citations.size() 0→citations.size(),我们统计范围内每个引用数(范围外放在边界)的出现次数,之后从分数高到低依次累加文章出现次数,找到累加文章数>=当前分数的第一个位置,当前分数即为最大h指数。
细节看代码。
class Solution_sort {
public:
int hIndex(vector<int>& citations) {
int n = citations.size();
int hindex = 0;
sort(citations.begin(), citations.end());
for(int i=0;i<citations.size();i++){
if(citations[i] >= n-i){
hindex = n-i;
break;
}
}
return hindex;
};
class Solution_count {
int n = citations.size();
int hindex = 0;
vector<int> counter(n+1);
for(int cite: citations) counter[(cite>n)?n:cite]++;
for(int i = n; i >= 0; i--){
hindex += counter[i];
if(hindex >= i) return i;
}
return 0;
}
class Solution_bisearch {
public:
bool check(vector<int>& citations, int x){
int cnt = 0;
for(int cite:citations) if(cite >= x) cnt++;
return cnt>=x;
}
int hIndex(vector<int>& citations) {
int n=citations.size();
int l=0,r=n;
while(l<r){
int mid = (l+r+1) >> 1; // 防止自循环
if(check(citations, mid)) l = mid; //落在[mid, r]
else r = mid-1;//落在[l,mid)
}
return r;
}
};