比较套路的题目,我们可以使用两个变量来分别维护已枚举的前缀中的最大值和当前的最大差值。我们从左到右遍历数组,更新这两个变量,并在每次迭代中计算当前的最优解。最终返回结果即可。
查看更多...
挺简单的题目,按题目的操作,字符串中所出现的每个字母最终都会减少到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]
left
l
right
r
r - l
比较简单的模拟题,使用一个大小为m的数组记录每个小球当前所在的列(使用-1表示球已经被卡住),遍历每一轮(其实就是遍历每一行),分情况计算每一个小球的下一轮(行)的位置:
m
-1
如果所在的单元格为1(形状为\),且小球处于最后一列或者右边的单元格为-1(形状为/),则卡住;
\
/
如果所在的单元格为-1(形状为/),且小球处于第一列或者右边的单元格为1(形状为\),则卡住;
否则,小球下一行的位置为当前位置 + 单元格值。
当前位置 + 单元格值
注意这里的组合并非是连续元素。可以得知,如果组合中的按位与结果不为0,说明这些元素至少有一个比特位全为1(只有这里才能保证按位与后至少有一个比特位不为0)。因此,我们可以统计每个元素的每个比特位的1的个数,然后取最大值即可。