1089.复写零
题目描述
给你一个长度固定的整数数组 arr
,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
注意:请不要在超过该数组长度的位置写入元素。
要求:请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。
示例1:
输入:[1,0,2,3,0,4,5,0]
输出:null
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]
示例2:
输入:[1,2,3]
输出:null
解释:调用函数后,输入的数组将被修改为:[1,2,3]
提示:
- 1 <= arr.length <= 10000
- 0 <= arr[i] <= 9
参考思路
以空间换时间,利用新数组覆盖旧数组。
参考代码
class Solution {
public:
void duplicateZeros(vector<int>& arr)
{
vector<int> ans;
int n=arr.size();
int count=0;
for(auto x:arr)
{
if(x)
ans.push_back(x);
else
{
ans.push_back(0);
count++;
if(count==n)
break;
ans.push_back(0);
}
count++;
if(count==n)
break;
}
copy(ans.begin(),ans.end(),arr.begin());
}
};
1090.受标签影响的最大值
题目描述
我们有一个项的集合,其中第 i
项的值为 values[i]
,标签为 labels[i]
。
我们从这些项中选出一个子集 S
,这样一来:
|S| <= num_wanted
- 对于任意的标签
L
,子集S
中标签为L
的项的数目总满足<= use_limit
。
返回子集 S
的最大可能的 和。
示例1:
输入:values = [5,4,3,2,1], labels = [1,1,2,2,3], num_wanted = 3, use_limit = 1
输出:9
解释:选出的子集是第一项,第三项和第五项。
示例2:
输入:values = [5,4,3,2,1], labels = [1,3,3,3,2], num_wanted = 3, use_limit = 2
输出:12
解释:选出的子集是第一项,第二项和第三项。
示例3:
输入:values = [9,8,8,7,6], labels = [0,0,0,1,1], num_wanted = 3, use_limit = 1
输出:16
解释:选出的子集是第一项和第四项。
示例4:
输入:values = [9,8,8,7,6], labels = [0,0,0,1,1], num_wanted = 3, use_limit = 2
输出:24
解释:选出的子集是第一项,第二项和第四项。
提示:
- 1 <= values.length == labels.length <= 20000
- 0 <= values[i], labels[i] <= 20000
- 1 <= num_wanted, use_limit <= values.length
参考思路
采用贪心策略,选择允许的标签数下的最大元素。具体步骤如下:
- 将元素的索引按照其value由大到小的顺序排序
- 遍历排序后的索引,获取其对应的值,标签
- 如果当前子集元素数小于需要的元素数目
- 如果当前标签出现次数小于允许的次数,则将索引对应的值选入子集,更新子集元素数目,并计算和。
参考代码
class Solution {
public:
int largestValsFromLabels(vector<int>& values, vector<int>& labels, int num_wanted, int use_limit)
{
int n=values.size();
vector<int> p(n);
for(int i=0;i<n;++i)
p[i]=i;
sort(p.begin(),p.end(),[&](int i,int j){return values[i]>values[j];});
unordered_map<int,int> H;
int cur=0,sum=0;
for(int i=0;i<n;++i)
{
int k=p[i];
int v=values[k];
int l=labels[k];
if(cur<num_wanted)
{
if(H[l]<use_limit)
{
H[l]++;
cur++;
sum+=v;
}
}
}
return sum;
}
};
1091.二进制矩阵中的最短路径
题目描述
在一个 N × N 的方形网格中,每个单元格有两种状态:空(0)或者阻塞(1)。
一条从左上角到右下角、长度为 k
的畅通路径,由满足下述条件的单元格 C_1, C_2, ..., C_k
组成:
- 相邻单元格
C_i
和C_{i+1}
在八个方向之一上连通(此时,C_i
和C_{i+1}
不同且共享边或角) C_1
位于 (0,0)(即,值为grid[0][0]
)C_k
位于(N-1, N-1)
(即,值为grid[N-1][N-1]
)- 如果
C_i
位于(r, c)
,则grid[r][c]
为空(即,grid[r][c] == 0
)
返回这条从左上角到右下角的最短畅通路径的长度。如果不存在这样的路径,返回 -1 。
示例1:
示例2:
提示:
1 <= grid.length == grid[0].length <= 100
grid[i][j] 为 0 或 1
参考思路
采用广度优先搜索方法求解。
具体实现过程见代码。
参考代码
const int INF=1000000000;
//搜索方向:左下,左,坐上,下,上,右下,右,右上
int dx[]={-1,-1,-1,0,0,1,1,1};
int dy[]={-1,0,1,-1,1,-1,0,1};
class Solution
{
public:
using pii=pair<int,int>;
int shortestPathBinaryMatrix(vector<vector<int>>& grid)
{
int n=grid.size();
if(grid[0][0]||grid[n-1][n-1])
return -1;
int **d=new int*[n];
for(int i=0;i<n;++i)
d[i]=new int[n];
for (int i = 0; i < n; ++ i)
for (int j = 0; j < n; ++ j)
d[i][j] = INF;
queue<pii> Q;
d[0][0]=0;
Q.push(pii(0,0));
while(!Q.empty())
{
int x=Q.front().first;
int y=Q.front().second;
Q.pop();
for(int i=0;i<8;++i)
{
int tx=x+dx[i],ty=y+dy[i];
if(0<=tx&&tx<n&&0<=ty&&ty<n&&!grid[tx][ty]&&d[tx][ty]>d[x][y]+1)
{
d[tx][ty]=d[x][y]+1;
Q.push(pii(tx,ty));
}
}
}
int ans=d[n-1][n-1];
delete []d;
if(ans==INF)
return -1;
return ans+1;
}
};
1092.最短公共超序列
题目描述
给出两个字符串 str1
和 str2
,返回同时以 str1
和 str2
作为子序列的最短字符串。如果答案不止一个,则可以返回满足条件的任意一个答案。
(如果从字符串 T 中删除一些字符(也可能不删除,并且选出的这些字符可以位于 T 中的 任意位置),可以得到字符串 S,那么 S 就是 T 的子序列)
示例:
输入:str1 = "abac", str2 = "cab"
输出:"cabac"
解释:
str1 = "abac" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 的第一个 "c"得到 "abac"。
str2 = "cab" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 末尾的 "ac" 得到 "cab"。
最终我们给出的答案是满足上述属性的最短字符串。
提示:
- 1 <= str1.length, str2.length <= 1000
- str1 和 str2 都由小写英文字母组成。
参考思路
此题可拆成两部分,即求两个字符串的最长公共子序列和字符串拼接。
最长公共子序列
python表示:
def lcs(str1, str2):
n, m = len(str1), len(str2)
dp = [[""] * (m + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(1, m + 1):
if str1[i - 1] == str2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + str1[i - 1]
else:
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j], key=len)
# print(dp)
return dp[-1][-1]
字符串拼接
python表示:
res = ""
i = 0
j = 0
for c in lcs(str1, str2):
while str1[i] != c:
res += str1[i]
i += 1
while str2[j] != c:
res += str2[j]
j += 1
res += c
i += 1
j += 1
return res + str1[i:] + str2[j:]
参考代码
大神的代码
const int INF = 1000000000;
class Solution {
public:
using pii = pair<int, int>;
string shortestCommonSupersequence(string s, string t) {
int n = s.size();
int m = t.size();
int F[n+1][m+1];
int pre[n+1][m+1];
for (int i = 0; i <= n; ++ i)
for (int j = 0; j <= m; ++ j)
{
F[i][j] = INF;
pre[i][j] = 0;
}
F[0][0] = 0;
queue<pii> Q;
Q.push(pii(0, 0));
while (!Q.empty())
{
int x = Q.front().first;
int y = Q.front().second;
Q.pop();
if (x < n && y < m && s[x] == t[y] && F[x+1][y+1] > F[x][y]+1)
{
F[x+1][y+1] = F[x][y]+1;
pre[x+1][y+1] = 0;
Q.push(pii(x+1, y+1));
}
if (x < n && F[x+1][y] > F[x][y]+1)
{
F[x+1][y] = F[x][y]+1;
pre[x+1][y] = 1;
Q.push(pii(x+1, y));
}
if (y < m && F[x][y+1] > F[x][y]+1)
{
F[x][y+1] = F[x][y]+1;
pre[x][y+1] = 2;
Q.push(pii(x, y+1));
}
}
/*
for (int i = 0; i <= n; ++ i)
{
for (int j = 0; j <= m; ++ j)
{
printf("(%d,%d)", F[i][j], pre[i][j]);
}
puts("");
}
*/
string ret;
for (int x = n, y = m; x != 0 || y != 0; )
{
if (pre[x][y] == 0)
{
x --;
y --;
ret += s[x];
}
else if (pre[x][y] == 1)
{
x --;
ret += s[x];
}
else if (pre[x][y] == 2)
{
y --;
ret += t[y];
}
//printf("%d %d\n", x, y);
}
reverse(ret.begin(), ret.end());
return ret;
}
};