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. 1 <= arr.length <= 10000
  2. 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. 1 <= values.length == labels.length <= 20000
  2. 0 <= values[i], labels[i] <= 20000
  3. 1 <= num_wanted, use_limit <= values.length

参考思路

采用贪心策略,选择允许的标签数下的最大元素。具体步骤如下:

  1. 将元素的索引按照其value由大到小的顺序排序
  2. 遍历排序后的索引,获取其对应的值,标签
  3. 如果当前子集元素数小于需要的元素数目
    1. 如果当前标签出现次数小于允许的次数,则将索引对应的值选入子集,更新子集元素数目,并计算和。

参考代码

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_iC_{i+1} 在八个方向之一上连通(此时,C_iC_{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. 1 <= grid.length == grid[0].length <= 100
  2. 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.最短公共超序列

题目描述

给出两个字符串 str1str2,返回同时以 str1str2 作为子序列的最短字符串。如果答案不止一个,则可以返回满足条件的任意一个答案。

(如果从字符串 T 中删除一些字符(也可能不删除,并且选出的这些字符可以位于 T 中的 任意位置),可以得到字符串 S,那么 S 就是 T 的子序列)

示例:

输入:str1 = "abac", str2 = "cab"
输出:"cabac"
解释:
str1 = "abac" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 的第一个 "c"得到 "abac"。 
str2 = "cab" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 末尾的 "ac" 得到 "cab"。
最终我们给出的答案是满足上述属性的最短字符串。

提示:

  1. 1 <= str1.length, str2.length <= 1000
  2. 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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值