Leetcode 第 397 场周赛题解

Leetcode 第 397 场周赛题解

题目1:3146. 两个字符串的排列差

思路

模拟。

因为每个字符串中的字符都不重复,所以用一个哈希表统计字符串 s 中字符和下标,再遍历字符串 t 计算每个字符在两个字符串中位置的绝对差值之和。

代码

class Solution
{
public:
	int findPermutationDifference(string s, string t)
	{
		int n = s.length();
		int diff = 0;
		unordered_map<char, int> idx;
		for (int i = 0; i < n; i++)
			idx[s[i]] = i;
		for (int i = 0; i < n; i++)
			diff += abs(i - idx[t[i]]);
		return diff;
	}
};

复杂度分析

时间复杂度:O(n),其中 n 是字符串 s 的长度。

空间复杂度:O(n),其中 n 是字符串 s 的长度。

题目2:

思路

外层循环枚举魔法师序列的末端,内层循环从魔法师序列的末端开始,往前间隔 k 累加求和。

因为有些魔法师可能会给你负能量,所以每累加一次能量,就要更新答案的最大值。

最后返回答案。

代码

class Solution
{
public:
	int maximumEnergy(vector<int> &energy, int k)
	{
		int n = energy.size();
		int ans = INT_MIN;
		for (int i = n - k; i < n; i++)
		{
			int sum = 0;
			for (int j = i; j >= 0; j -= k)
			{
				sum += energy[j];
				ans = max(ans, sum);
			}
		}
		return ans;
	}
};

复杂度分析

时间复杂度:O(n),其中 n 为数组 energy 的长度。

空间复杂度:O(1)。

题目3:3148. 矩阵中的最大得分

思路

动态规划。

设经过的方格为 c1, c2, ⋯ , ck,那么得分为 (c2−c1)+(c3−c2)+⋯+(ck−ck−1)=ck−c1,也就是说得分只和路径上第一个方格以及最后一个方格有关。

因此问题变为:给一个矩阵,每次可以往右或往下走,求终点值-起点值的最大值。

设 dp[i][j] 表示以 (i,j) 为终点,起点的最小值,它显然是 dp[i - 1][j]、dp[i][j - 1]、grid[i][j] 三者的最小值,转移方程为:dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), grid[i][j])。

遍历 grid,每次先求以 (i,j) 为终点,起点的最小值 minGrid = min(dp[i - 1][j], dp[i][j - 1]),然后计算终点值-起点值的最大值 ans = max(ans, grid[i][j] - minGrid),最后更新 dp[i][j] = min(grid[i][j], minGrid)。

最后返回 ans。

代码

/*
 * @lc app=leetcode.cn id=3148 lang=cpp
 *
 * [3148] 矩阵中的最大得分
 */

// @lc code=start
class Solution
{
public:
    int maxScore(vector<vector<int>> &grid)
    {
        int m = grid.size(), n = m ? grid[0].size() : 0;
        // dp[i][j] 表示以 (i,j) 为终点,起点的最小值
        int dp[m][n];
        memset(dp, INT_MAX, sizeof(dp));
        int ans = INT_MIN;
        // 状态转移
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
            {
                int minGrid = INT_MAX;
                if (i > 0)
                    minGrid = min(minGrid, dp[i - 1][j]);
                if (j > 0)
                    minGrid = min(minGrid, dp[i][j - 1]);
                ans = max(ans, grid[i][j] - minGrid);
                dp[i][j] = min(grid[i][j], minGrid);
            }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(m*n),其中 m 和 n 分别是矩阵 grid 的行数和列数。

空间复杂度:O(m*n),其中 m 和 n 分别是矩阵 grid 的行数和列数。

题目4:3149. 找出分数最低的排列

思路

状压 DP。

题解:状压 DP:从记忆化搜索到递推(Python/Java/C++/Go)

代码

/*
 * @lc app=leetcode.cn id=3149 lang=cpp
 *
 * [3149] 找出分数最低的排列
 */

// @lc code=start
class Solution
{
public:
    vector<int> findPermutation(vector<int> &nums)
    {

        int n = nums.size();
        vector<vector<int>> memo(1 << n, vector<int>(n, -1)); // -1 表示没有计算过
        // s 表示前面已选的下标集合,j 表示上一个位置的下标
        function<int(int, int)> dfs = [&](int s, int j) -> int
        {
            if (s == (1 << n) - 1)
            { // 所有位置都填完了,最后一个位置是下标 j
                return abs(j - nums[0]);
            }
            int &res = memo[s][j]; // 注意这里是引用
            if (res != -1)
            { // 之前计算过
                return res;
            }
            res = INT_MAX;
            // 枚举当前位置填下标 k
            for (int k = 1; k < n; k++)
            {
                if ((s >> k & 1) == 0)
                { // k 之前没填过
                    res = min(res, dfs(s | 1 << k, k) + abs(j - nums[k]));
                }
            }
            return res;
        };

        vector<int> ans;
        // 找到最佳路径
        function<void(int, int)> make_ans = [&](int s, int j) -> void
        {
            ans.push_back(j);
            if (s == (1 << n) - 1)
                return;
            int final_res = dfs(s, j);
            for (int k = 1; k < n; k++)
            {
                if ((s >> k & 1) == 1)
                { // k 之前填过
                    continue;
                }
                if (dfs(s | 1 << k, k) + abs(j - nums[k]) == final_res)
                {
                    make_ans(s | 1 << k, k);
                    break;
                }
            }
        };
        make_ans(1, 0);
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n22n),其中 n 是数组 nums 的长度。

空间复杂度:O(n2n),其中 n 是数组 nums 的长度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值