滑动窗口的套路题目,窗口左侧每移动一位,右侧移到刚好满足条件,然后右侧后面所有的子数组都能满足条件,简单来说做法就是在每次(外层)循环中:
窗口左侧指针left向右移动一位;
left
窗口右侧指针right向右移动,直到窗口满足条件,此时所有以left为左端点、right直到n为右端点的子数组都满足条件;
right
n
查看更多...
同样是滑动窗口的套路题目,窗口左侧每移动一位,右侧移到刚好满足条件,然后右侧后面所有的子数组都能满足条件。具体思路可以参考2962题。
比较套路的题目,我们可以使用两个变量来分别维护已枚举的前缀中的最大值和当前的最大差值。我们从左到右遍历数组,更新这两个变量,并在每次迭代中计算当前的最优解。最终返回结果即可。
挺简单的题目,按题目的操作,字符串中所出现的每个字母最终都会减少到1个,所以我们只需要统计字符串中不同字母的数量即可。
1
动态规划题目,我们可以使用一个一维数组dp来记录从当前题目开始到最后一题的最大分数。从后往前遍历,对于每个题目,有两种选择:选择当前题目或者跳过当前题目。我们需要根据题目的分数和脑力消耗来更新dp数组。最终返回dp[0]即可。
dp
dp[0]
不考虑边界条件的情况下,状态转移方程为:dp[i] = max(dp[i + 1], questions[i][0] + dp[i + questions[i][1] + 1]),其中questions[i][0]表示当前题目的分数,questions[i][1]表示当前题目的脑力消耗(即跳过的题目数量)。
dp[i] = max(dp[i + 1], questions[i][0] + dp[i + questions[i][1] + 1])
questions[i][0]
questions[i][1]
使用两个指针维护当前字符串s的索引和空格数组spaces的索引。我们从左到右遍历字符串s,如果当前s的索引等于空格数组中索引指向的位置,则在结果字符串中添加一个空格,并将空格数组的索引加一(往右移动到下一个需要加空格的地方)。按需处理完空格后,将当前字符添加到结果字符串中。最终返回结果字符串即可。
s
spaces
简单的回溯模板题,在backtrace函数中,我们需要遍历所有可能的子集,并计算它们的异或和。我们可以通过递归来实现这个过程,每次递归时,我们有两个选择:选择当前元素或者不选择当前元素。最终,我们将所有子集的异或和相加,得到结果。
backtrace
不难想,但实现起来还是需要注意很多细节。首先,我们需要一个链表来记录未使用的区块,每次分配内存时,我们需要遍历链表找到一个合适的区块。其次,我们需要一个哈希表来记录已使用的区块,以便于释放内存时能够快速找到对应的区块。最后,我们在释放内存时,将归还的内存作为一个新的区块插入到链表中,然后需要注意合并左右相邻的区块。
经典动态规划题,就地使用grid数组记录到达每个位置的最小路径和,最后返回grid[m - 1][n - 1]即可。状态转移方程为:
grid
grid[m - 1][n - 1]
如果r == 0 && c == 0(起始点),则grid[r][c]不变;
r == 0 && c == 0
grid[r][c]
如果r == 0 && c != 0(第一行),则grid[r][c]加上grid[r][c - 1];
r == 0 && c != 0
grid[r][c - 1]
如果r != 0 && c == 0(第一列),则grid[r][c]加上grid[r - 1][c];
r != 0 && c == 0
grid[r - 1][c]
否则,grid[r][c]加上min(grid[r - 1][c], grid[r][c - 1])。
min(grid[r - 1][c], grid[r][c - 1])
一开始想到的是前缀和的思路,但由于题目并非是针对某种小数据集的查询(比如小写字母),而是任意数字,因此前缀和会占用大量的空间。因此,我们可以使用哈希表来记录每个数字所出现的位置,然后对于每次查询,使用二分查找来计算区间内的频率:对于查询区间[left, right],我们先找到第一个大于等于left的位置l,然后找到第一个大于right的位置r,则出现的频率为r - l。
[left, right]
l
r
r - l