LeetCode 第 141 场周赛 【复写零】【受标签影响的最大值】【二进制矩阵中的最短路径 显示英文描述】【最短公共超序列】

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;
                }
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值