1310. 子数组异或查询
题解思路
使用前缀和
403. 青蛙过河
题解思路
我的问题是找不到dp值代表了什么.找不到状态转移方程
dp[i][k]代表了我是从[j]跳了k步到这里的,[j]有哪几种状态呢,从前面的状态跳了k + 1
, k
, k - 1
步到[j]
,[j]
才有可能跳(k + 1) - 1
,k
,(k - 1) + 1
步到[i]
dp[i][k] = dp[j][k - 1] || dp[j][k] || dp[j][k + 1];
需要注意的地方
1.k > j+1时,是不可能从j
跳到i
的
2.因为是覆盖dp,所以j
从i - 1
到0
遍历
for (int i = 1; i < n; ++i) {
for (int j = i - 1; j >= 0; --j) {
int k = stones[i] - stones[j];
if (k > j + 1) break;
dp[i][k] = dp[j][k - 1] || dp[j][k] || dp[j][k + 1];
if (i == n - 1 && dp[i][k]) return true;
}
}
下面的是正向思路,可能会好理解一点
for (int i = 1; i < n; ++i) {
for (int j = i - 1; j >= 0; --j) {
int k = stones[i] - stones[j];
if (k > j + 1) break;
if (dp[j][k]) {
dp[i][k - 1] = true;
dp[i][k] = true;
dp[i][k + 1] = true;
}
if (i == n - 1 && dp[i][k]) return true;
}
}
633. 平方数之和
题解思路
暴力超时
使用双指针
while (a <= b) {
if (a * a + b * b == c) {
return true;
}
else if (a * a + b * b < c) {
a++;
}
else {
b--;
}
}
938. 二叉搜索树的范围和
我的思路
if (root != nullptr) {
rangeSumBST(root -> left, low, high);
if (root -> val >= low && root -> val <= high) {
sum += root -> val;
}
rangeSumBST(root -> right, low, high);
}
return sum;
我本来的思路是从>= low开始 >=high结束的,这样似乎也是要加条件语句,我在最前面加了,时间并没有少多少,所以这题有什么意思?
1011. 在 D 天内送达包裹的能力
题解思路
本来以为运力一点一点加上去这样暴力的做法是不可以的
第二个问题是不知道具体地处理某一运力下天数的做法
暴力是可以的,只不过需要用二分来优化
1.left为最小运力maxelem
,right为最大运力sumvec
2.在left
和right
中间有一个最小运力,使得所需天数==D
3.使用cur表示当前的货物量,货物量 > mid
,所需的天数++(这里使用了>的小技巧,如果使用<=作为判断条件,需要写的会多一点)
4.所需天数>D,运力不够,left = mid + 1
,所需天数<= D,运力说不定还能再减一点.right = mid
int left = *max_element(weights.begin(), weights.end()), right = accumulate(weights.begin(), weights.end(), 0);
while (left < right) {
int mid = (left + right) / 2;
int need = 1, cur = 0;
for (int weight : weights) {
if (cur + weight > mid) {
need++;
cur = 0;
}
cur += weight;
}
if (need <= D) {
right = mid;
}
else if (need > D) {
left = mid + 1;
}
}
377. 组合总和 Ⅳ
我的思路
使用回溯方法,但是超时了。想要用记忆化递归,但是不知道存的是什么。
后来想了想存的是target,但是还是超时了
int sum(vector<int> & nums, int target) {
if (target < 0) {
return 0;
}
else if (target == 0) {
return 1;
}
else if (mem[target] != 0){
return mem[target];
}
int cnt = 0;
for (int i = 0; i < nums.size(); ++i) {
if (target >= nums[i])
cnt += combinationSum4(nums, target - nums[i]);
}
mem[target] = cnt;
return cnt;
}
题解思路
使用动态规划
vector<int> dp(target + 1, 0);
dp[0] = 1;
for (int i = 1; i <= target; ++i) {
for (const int& num : nums) {
if (i - num >= 0 && dp[i] < INT_MAX - dp[i - num])
dp[i] += dp[i - num];
}
}
return dp[target];
使用限定条件INT_MAX - dp[i - num]
去除比如说990的cnt比999要大且990 的cnt > INT_MAX的情况
368. 最大整除子集
题解思路
序列dp
使用f[]存最大长度,使用g[]存下标.j∈[0,i)
如果可以整除并且f[j] + 1 > len
就修改保存,遍历完j在[i]后保存len长度和prev下标.
即[i]下存着前一个可以整除的下标
需要注意的地方,初始化prev应该是i,我初始化为0是错误的,当它没有可以整除的数或者被作为第一个被整除的数的时候,存的下标应为自己.
for (int i = 0; i < n; ++i) {
int len = 1, prev = i;
for (int j = 0; j < i; ++j) {
if (nums[i] % nums[j] == 0) {
if (f[j] + 1 > len) {
len = f[j] + 1;
prev = j;
}
}
}
f[i] = len;
g[i] = prev;
}
363. 矩形区域不超过 K 的最大数值和
我的思路
使用二维最大前缀和暴力解
for (int i = 1; i <= row; ++i) {
for (int j = 1; j <= col; ++j) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1];
}
}
for (int i = 0; i <= row; ++i) {
for (int j = 0; j <= col; ++j) {
for (int ii = i + 1; ii <= row; ++ii) {
for (int jj = j + 1; jj <= col; ++jj) {
int tmp = dp[ii][jj] - dp[ii][j] - dp[i][jj] + dp[i][j];
if (tmp <= k)
maxmatrix = max(maxmatrix, tmp);
}
}
}
}
需要注意的是,前缀和矩阵不能从i``j
开始从i + 1``j + 1
开始才是一个边长为1的矩形,不然的话k < 0 ,结果找到一个0max就为0了
题解思路
先固定左边一排,右列逐渐向右。
通过最大连续子数组来剪枝,效果还挺好。最大连续子数组的max初始值记得设置为nums[0]
,不然,无论max是INT_MIN的话放dp上面还是下面都不好受
91. 解码方法
我的思路
分析一下,本题就是一个有条件的斐波那契数列,改了好久
例如
121 分为1 21 和12 1 f(n) = f(n - 1) + f(n - 2)
for (int i = 1; i < s.size(); ++i) {
if (s[i] == '0') {
if (s[i - 1] != '1' && s[i - 1] != '2') {
return 0;
}
else {
dp[i + 1] = dp[i - 1];
}
}
else {
if (s[i - 1] == '1' || s[i - 1] == '2' && s[i] - '0' < 7) {
dp[i + 1] = dp[i] + dp[i - 1];
}
else {
dp[i + 1] = dp[i];
}
}
}
28. 实现 strStr()
题解思路
KMP算法、暴力算法、BM算法
27. 移除元素
我的思路
使用pre作为新数组的最后一个元素。
220. 存在重复元素 III
####### 题解思路
我的想法是维护一个k宽度的map,因为map有自动排序功能,进一个出一个比较一个。
看了题解,思路没问题,就是自动排序也可以选择set
for (int i = 0; i < len; ++i) {
auto iter = s.lower_bound((long long)nums[i] - t);
if (iter != s.end() && *iter <= (long long)nums[i] + t) {
return true;
}
s.insert(nums[i]);
if (i >= k) { //可用s.size() > k来替换
s.erase(nums[i - k]);
}
}
- 在排序好的set中查找到第一个大于等于nums[i] - t的位置,如果他存在且值小于num[i] + 1,就说明有这样的值
- 注意等于号,包括
i >= k
.*ter <= (long long)nums[i] + t
87. 扰乱字符串
思路
https://leetcode-cn.com/problems/scramble-string/solution/di-gui-by-powcai/
做递归,使用哈希表来完成记忆化递归,避免超时
213. 打家劫舍 II
我的思路
- 不偷第一间
- 不偷最后一间
max(dp2[len - 1], dp[len - 2]);
我还以为可以一次遍历解决的.然后发现题解和我的思路一样
208. 实现 Trie (前缀树)
思路
使用 next[26] 作为搜索节点、bool isend保存单词的终点。
783. 二叉搜索树节点最小距离
思路
中序遍历,两两相减的最小值
int minnum = INT_MAX;
void dfs(TreeNode* root) {
if (root == nullptr) {
return;
}
if (root -> left) {
dfs(root -> left);
}
if (prev != nullptr)
minnum = min(minnum,root -> val - prev -> val);
prev = root;
if (root -> right){
dfs(root -> right);
}
}
179. 最大数
难点
转数字为字符串后 30 > 3 ==> 303 实际330更大
3331 > 3 ==> 33313 实际应为33331
以数位比较复杂繁琐,使用模拟的方法会更简易
cmp ==> s1 + s2 > s2 + s1
知识点
- sort 比较默认从小到大
- sort cmp函数return简单易记的方法 ,
大于(>)就是降序,小于(<)就是升序,
bool (int& a , int& b) {
return a>b;
}
- string字符串比较按ASCII码进行
264. 丑数 II
思路1
- 使用map(不重复排序),每一次去除第一个a,放入2a,3a,5a。
思路2
- 三指针,
1.num2 = p2×2,num3 = p3×3,num5 = p5 × 5
1.dp[i] = num2 num3 num5的最小值
2.dp[i] == numx, px++
153. 寻找旋转排序数组中的最小值
思路
二分
74. 搜索二维矩阵
思路
由上到下,由左到右分别进行二分搜索
https://mp.weixin.qq.com/s/M1KfTfNlu4OCK8i9PSAmug
[left,right]
right = size() - 1;
while ( <= )
mid = left + (right - left) / 2
if (target < mid)
right = mid - 1
if (target > mid)
left = mid + 1
else
return mid;
return -1
[left, right)
[1,2,2,2,2,2,3] #搜索到最左边的2
right = size()
while ( < )
mid = left + (right - left) / 2
if (target < mid)
right = mid
if (target > mid)
left = mid + 1
else
right = mid;
return left
190. 颠倒二进制位
思路
输入 n 最右边的一位,赋给ans上它原本位置的对称位,右移一位。
191. 位1的个数
tips
-
n & (n - 1)
使得最低位的1翻转
92. 反转链表 II
tips
- 确定首尾状态的cur节点情况,然后再讨论中间经过了哪些过程。
115. 不同的子序列
54. 螺旋矩阵
tips
- 使用矩阵元素个数来计算终点
我的做法
- 使用switch模拟方向这个状态的转换,使用当前坐标和缩小的边界比较作为停止条件。遇到了单列无法继续的问题。要加单列的额外处理。
- 其实这种做法忽略了状态改变的连续性,直接在while循环里依次添加不同方向的模拟循环即可,以可计算的矩阵元素数组作为截止条件
1178. 猜字谜
- 使用位来表示字符串
- 字符串的所有子集
while (n > 0)
n = (n - 1) & str
(对顺序和重复次数无要求时)
1.使用map以int类型表示word中每个字符串对应的数以及其出现的次数.
2.在map中找到puzzle[i]的子集.
303. 区域和检索 - 数组不可变
- 了解并掌握前缀和
304. 二维区域和检索 - 矩阵不可变
- 二维前缀和多使用行首零和列首零减少单行和单列的if判断
- 二维数组的动态定义
1047. 删除字符串中的所有相邻重复项
- 栈的性质
- 字符串的方法