题目1
给你一个大小为 m * n
的方阵 mat
,方阵由若干军人和平民组成,分别用 1 和 0 表示。
请你返回方阵中战斗力最弱的 k
行的索引,按从最弱到最强排序。
如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。
军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。
示例 1:
输入:mat = [[1,1,0,0,0], [1,1,1,1,0], [1,0,0,0,0], [1,1,0,0,0], [1,1,1,1,1]], k = 3 输出:[2,0,3] 解释: 每行中的军人数目: 行 0 -> 2 行 1 -> 4 行 2 -> 1 行 3 -> 2 行 4 -> 5 从最弱到最强对这些行排序后得到 [2,0,3,1,4]
示例 2:
输入:mat = [[1,0,0,0], [1,1,1,1], [1,0,0,0], [1,0,0,0]], k = 2 输出:[0,2] 解释: 每行中的军人数目: 行 0 -> 1 行 1 -> 4 行 2 -> 1 行 3 -> 1 从最弱到最强对这些行排序后得到 [0,2,3,1]
提示:
m == mat.length
n == mat[i].length
2 <= n, m <= 100
1 <= k <= m
matrix[i][j]
不是 0 就是 1
思路及代码
就是遍历+记录,没有什么好说的,使用map,key为军人数,value为索引的集合。
class Solution {
public:
vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
map<int,vector<int>> m;
int len = mat.size();
for(int i = 0;i < len;i++){
int count = 0;
for(int j = 0;j < mat[i].size();j++){
if(mat[i][j] == 1){
count++;
}else{
break;
}
}
m[count].push_back(i);
}
vector<int> ret;
int c = 0;
for (map<int,vector<int>>::iterator iter = m.begin();
iter != m.end();
++iter) {
vector<int> tmp = iter->second;
for(int j = 0;j < tmp.size();j++){
ret.push_back(tmp[j]);
c++;
if(c >= k){
return ret;
}
}
}
return ret;
}
};
题目2
有 N
堆石头排成一排,第 i
堆中有 stones[i]
块石头。
每次移动(move)需要将连续的 K
堆石头合并为一堆,而这个移动的成本为这 K
堆石头的总数。
找出把所有石头合并成一堆的最低成本。如果不可能,返回 -1
。
示例 1:
输入:stones = [3,2,4,1], K = 2 输出:20 解释: 从 [3, 2, 4, 1] 开始。 合并 [3, 2],成本为 5,剩下 [5, 4, 1]。 合并 [4, 1],成本为 5,剩下 [5, 5]。 合并 [5, 5],成本为 10,剩下 [10]。 总成本 20,这是可能的最小值。
示例 2:
输入:stones = [3,2,4,1], K = 3 输出:-1 解释:任何合并操作后,都会剩下 2 堆,我们无法再进行合并。所以这项任务是不可能完成的。.
示例 3:
输入:stones = [3,5,1,2,6], K = 3 输出:25 解释: 从 [3, 5, 1, 2, 6] 开始。 合并 [5, 1, 2],成本为 8,剩下 [3, 8, 6]。 合并 [3, 8, 6],成本为 17,剩下 [17]。 总成本 25,这是可能的最小值。
提示:
1 <= stones.length <= 30
2 <= K <= 30
1 <= stones[i] <= 100
思路及代码
首先有解的条件为(n-1)%(K-1)==0
dp[i][j][k]表示把 第i堆石头到第j堆石头合并为k堆的最小代价(初始化dp[i][i][1]=0,显然,在执行过程中dp[i][j][j-i+1]都为0)
我们可以枚举中间点m,把左边分为k-1堆,把右边分为1堆
那么我们有: dp[i][j][k] = min(dp[i][j][k], dp[i][m][k-1] + dp[m+1][j][1])
为什么不能是左边k-2堆,右边2堆呢?考虑右边合并为两堆,那么我们可以找一个点,划到左边,就还是左边k-1堆,右边1堆啦,所以其他所有的情况实际上都已经被 左边k-1堆,右边1堆覆盖了。
还有一个方程就是dp[i][j][1] = dp[i][j][K] + sum[j] - sum[i-1],注意是大写的K,就是说如果有K堆了,那么我们可以把它们合并为一堆,代价为这些石头的总和。
来源:https://www.cnblogs.com/ljy08163268/p/11784291.html
class Solution {
public:
int dp[50][50][50],pre[50];
int mergeStones(vector<int>& stones, int K) {
int n=stones.size();
if((n-K)%(K-1))return -1;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
dp[i][i][1]=0;
pre[i]=pre[i-1]+stones[i-1];
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int m=i;m<j;m++){
for(int k=2;k<=len;k++){
dp[i][j][k]=min(dp[i][j][k],dp[i][m][k-1]+dp[m+1][j][1]);
}
}
dp[i][j][1]=min(dp[i][j][1],dp[i][j][K]+pre[j]-pre[i-1]); //如果dp[l][r][K]不存在,那么也就是说明不能把[l,r]这一段区间合成一段
}
}
return dp[1][n][1];
}
};
题目3
如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,以下数列为等差数列:
1, 3, 5, 7, 9 7, 7, 7, 7 3, -1, -5, -9
以下数列不是等差数列。
1, 1, 2, 5, 7
数组 A 包含 N 个数,且索引从 0 开始。该数组子序列将划分为整数序列 (P0, P1, ..., Pk),P 与 Q 是整数且满足 0 ≤ P0 < P1 < ... < Pk < N。
如果序列 A[P0],A[P1],...,A[Pk-1],A[Pk] 是等差的,那么数组 A 的子序列 (P0,P1,…,PK) 称为等差序列。值得注意的是,这意味着 k ≥ 2。
函数要返回数组 A 中所有等差子序列的个数。
输入包含 N 个整数。每个整数都在 -231 和 231-1 之间,另外 0 ≤ N ≤ 1000。保证输出小于 231-1。
示例:
输入:[2, 4, 6, 8, 10] 输出:7 解释: 所有的等差子序列为: [2,4,6] [4,6,8] [6,8,10] [2,4,6,8] [4,6,8,10] [2,4,6,8,10] [2,6,10]
思路及代码
来源:https://blog.csdn.net/starlet_kiss/article/details/103284418
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
int n = A.size();
long long ans = 0;
vector<map<long long,int>> p(n);
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
long long delta = (long long)A[i] - (long long)A[j];
int sum = 0;
if (p[j].find(delta) != p[j].end()) {
sum = p[j][delta];
}
p[i][delta] += sum + 1;
ans += sum;
}
}
return (int)ans;
}
};
总结:DP,该不会的,就是不会