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
思路:使用一个指针,指针的左边全是已经做完成的元素,指针从左至右依次遍历,遇到0之后,先使用插入排序的思想,在后面插入一个0,后面的元素从末尾依次右移(当然最后一个元素被覆盖),指针向右移动两步(不再指向新添加的0),如果没有遇到0,指针移动一步。
public static void duplicateZeros(int[] arr) {
//遍历遇到0处理
int left=0;
while(left<=arr.length-2) {
if(arr[left]==0) {
//后面依次移动
for(int i=arr.length-1;i>=left+2;i--) {
arr[i]=arr[i-1];
}
arr[left+1]=0;
left=left+2;
}
else{
left++;
}
}
}
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
这道题真的是读题读了很久才读懂做什么,意思实际就是有很多标签,每个标签里面有很多值,题目给出的限制use_limit,就是要求每个标签最多只能选择use_limit个值,问一共选择num_wanted个值的最大总和是多少。
举例:values = [9,8,8,7,6], labels = [0,0,0,1,1], num_wanted = 3, use_limit = 2
即对于标签0,它对应的值有[9,8,8],对于标签1,它对应的值有[7,6],因为每个标签被限制只能选择2个,所以对每个标签建立一个大小为use_limit的最大堆。
得到标签0的最大堆为[9,8],得到标签1的最大堆为[7,6],所以在[9,8]+[7,6]中选择3个值(最大)
思路:优先队列(堆)+HashMap
构建一个每次取得队列最大值的优先队列,利用HashMap来记录我们取得的每种不同标签的数量,不能超过use_limit,当取到的元素达到num_wanted,则结束返回结果。
public int largestValsFromLabels(int[] values, int[] labels, int num_wanted, int use_limit) {
Map<Integer,Integer> map=new HashMap<>();
//优先队列--->o2[0]-o1[0]逆序
PriorityQueue<int[]> queue=new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o2[0]-o1[0];
}
});
//将(values[i],labels[i])依次放入优先队列,并且以(o2[0]-o1[0]),按照values来降序排
for (int i=0;i<values.length;i++)
{
queue.add(new int[]{values[i],labels[i]});
}
int res=0;
//取到足够的数量(num_wanted)则跳出循环
int cnt=0;
//没有限制,直接返回优先队列前num_wanted即可
if(use_limit==0) {
while (!queue.isEmpty()) {
int[] poll = queue.poll();
cnt++;
res+=poll[0];
if(cnt==num_wanted) {
return res;
}
}
}
//有限制
while (!queue.isEmpty())
{
//取出堆顶元素(value,label)----value最大
int[] poll = queue.poll();
//利用hashMap来记录我们取得的每个不同标签的数量,不能超过use_limit
if(map.containsKey(poll[1])&&map.get(poll[1])==use_limit) {
continue;
}else if(map.containsKey(poll[1])){//map.get(poll[1])<use_limit
map.put(poll[1], map.get(poll[1])+1);
cnt++;
res+=poll[0];
if(cnt==num_wanted) {
break;
}
}else {//!map.containsKey
map.put(poll[1], 1);
cnt++;
res+=poll[0];
if(cnt==num_wanted) {
break;
}
}
}
return res;
}
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 。
原题地址:https://leetcode-cn.com/contest/weekly-contest-141/problems/shortest-path-in-binary-matrix/
示例 1:
输入:[[0,1],[1,0]]
输出:2
示例 2:
输入:[[0,0,0],[1,1,0],[1,1,0]]
输出:4
思路:队列,先将[0,0]放入队列里面,然后每次扩展一步(向8个方向去找到是0的点),将满足的点继续入队作为下一层遍历的集合,如果那个点扩展先触碰到了(m-1,n-1),那么就是最短路径,即是相当于每一层扩散,先到的层则最短
public int shortestPathBinaryMatrix_02(int[][] grid) {
int m, n;
// 8个方向
int[][] direction = {{0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,-1},{-1,1}};
// 使用队列
Queue<int[]> queue = new LinkedList<>();
m = grid.length;
n = grid[0].length;
if (grid[0][0] == 1 || grid[m - 1][n - 1] == 1)
return -1;
// 将(0,0)点放入队列
queue.add(new int[] { 0, 0 });
int res = 0;
boolean[][] hasVisited = new boolean[m][n];
// 操作队列
while (!queue.isEmpty()) {
int size = queue.size();
res++;
// 扩散队列里面的点
for (int i = 0; i < size; i++) {
// 取出其中的一个点,依次向8个方向走一步,查看是否满足条件--->满足则放到队列里面等待下一轮又再次遍历它
int[] tmp = queue.poll();
int r, c;
for (int[] d : direction) {
r = tmp[0] + d[0];
c = tmp[1] + d[1];
// (r,c)下一个点的位置
if (r < 0 || c < 0 || r >= m || c >= n || grid[r][c] == 1 || hasVisited[r][c])
continue;
// 如果已经到底了,因为下一层的遍历触碰到了(m-1,n-1),那么就是最短路径,即是相当于每一层扩散,先到的层则最短
if (r == m - 1 && c == n - 1)
return res + 1;
queue.add(new int[] {r,c});
hasVisited[r][c] = true;
}
}
}
return -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 都由小写英文字母组成。
引用某位大佬的答案:
public String shortestCommonSupersequence(String str1, String str2) {
int maxL=str1.length()>str2.length()?str1.length():str2.length();
int[][] book=new int[maxL+5][maxL+5];
int[][] dp=new int[maxL+5][maxL+5];
lcs(str1,str2,dp,book);
StringBuilder sb = new StringBuilder();
char[] s1=str1.toCharArray();
char[] s2=str2.toCharArray();
getlcs(sb,s1,s2,str1.length(),str2.length(),book);
String s=sb.toString();
StringBuilder res=new StringBuilder();
int i=0,j=0;
for (char c:s.toCharArray())
{
while (i<s1.length&&s1[i]!=c)
{
res.append(s1[i++]);
}
while (j<s2.length&&s2[j]!=c)
{
res.append(s2[j++]);
}
res.append(c);
i++;
j++;
}
while (i<s1.length)
{
res.append(s1[i++]);
}
while (j<s2.length)
{
res.append(s2[j++]);
}
return res.toString();
}
private void getlcs(StringBuilder sb, char[] s1, char[] s2, int i, int j, int[][] book) {
if(i==0||j==0)return;
if(book[i][j]==0)
{
getlcs(sb,s1,s2,i-1,j-1,book);
sb.append(s1[i-1]);
}
else if(book[i][j]==1)
{
getlcs(sb,s1,s2,i-1,j,book);
}
else
{
getlcs(sb,s1,s2,i,j-1,book);
}
}
private void lcs(String str1, String str2, int[][] dp, int[][] book) {
for (int i=1;i<=str1.length();i++)
{
for (int j=1;j<=str2.length();j++)
{
if(str1.charAt(i-1)==str2.charAt(j-1))
{
dp[i][j]=dp[i-1][j-1]+1;
book[i][j]=0;
}
else if(dp[i-1][j]>=dp[i][j-1])
{
dp[i][j]=dp[i-1][j];
book[i][j]=1;
}
else
{
dp[i][j]=dp[i][j-1];
book[i][j]=-1;
}
}
}
}