啊......已经没有时间说其他的了。
LeetCode376: 摆动序列
思路:设置翻转参数,确定上下or下上流程。
class Solution {
public:
int wiggleMaxLength(vector& nums) {
int res = 0;
int reverse = 0; //初始不知道第一次会上坡还是下坡
for(int i = 1; i < nums.size(); i++){
if(nums[i-1]nums[i] && reverse != 2){
res++;
reverse = 2;//记录下坡了
}
}
return res + 1; //res是两两比较得来的值,差一个边界值要+1
}
};
作者:柯慕灵
链接:https://leetcode.cn/problems/wiggle-subsequence/solutions/2150956/yi-bian-bian-li-qiu-jie-chao-jian-dan-zh-thd7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode738: 单调递增的数字
思路:从左往右遍历各位数字,找到第一个开始下降的数字[i],将[i]减1,然后将[i+1 ...]各位数字全部置为9即可例如:1232123,从左往右遍历,找到第一个开始下降的数字3,将3改为2,然后将后面所有数字全部置为9,最后为:1229999 即为答案
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strn = to_string(n);
int i = 1;
while(i=2&&strn[i-2]==strn[i-1]) i--;
strn[i-1] = strn[i-1] - 1;
for(;i
LeetCode55: 跳跃游戏
思路:如果某一个作为 起跳点 的格子可以跳跃的距离是 3,那么表示后面 3 个格子都可以作为 起跳点 。可以对每一个能作为 起跳点 的格子都尝试跳一次,把 能跳到最远的距离 不断更新。如果可以一直跳到最后,就成功了。
class Solution {
public:
bool canJump(vector& nums) {
int k = 0;
for (int i = 0; i < nums.size(); i++) {
if (i > k) return false;
k = max(k, i + nums[i]);
}
return true;
}
};
作者:Ikaruga
链接:https://leetcode.cn/problems/jump-game/solutions/24322/55-by-ikaruga/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode45: 跳跃游戏II
每一次跳跃用for循环模拟。
int jump(vector &nums)
{
int ans = 0;
int start = 0;
int end = 1;
while (end < nums.size())
{
int maxPos = 0;
for (int i = start; i < end; i++)
{
// 能跳到最远的距离
maxPos = max(maxPos, i + nums[i]);
}
start = end; // 下一次起跳点范围开始的格子
end = maxPos + 1; // 下一次起跳点范围结束的格子
ans++; // 跳跃次数
}
return ans;
}
作者:Ikaruga
链接:https://leetcode.cn/problems/jump-game-ii/solutions/36035/45-by-ikaruga/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode452: 用最少数量的箭引爆气球
思路:考虑所有气球中右边界位置最靠左的那一个,那么一定有一支箭的射出位置就是它的右边界。
class Solution {
public:
int findMinArrowShots(vector>& points) {
if (points.empty()) {
return 0;
}
sort(points.begin(), points.end(), [](const vector& u, const vector& v) {
return u[1] < v[1];
});
int pos = points[0][1];
int ans = 1;
for (const vector& balloon: points) {
if (balloon[0] > pos) {
pos = balloon[1];
++ans;
}
}
return ans;
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/solutions/494515/yong-zui-shao-shu-liang-de-jian-yin-bao-qi-qiu-1-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode56: 合并区间
思路:排序
class Solution {
public:
vector> merge(vector>& intervals) {
if (intervals.size() == 0) {
return {};
}
sort(intervals.begin(), intervals.end());
vector> merged;
for (int i = 0; i < intervals.size(); ++i) {
int L = intervals[i][0], R = intervals[i][1];
if (!merged.size() || merged.back()[1] < L) {
merged.push_back({L, R});
}
else {
merged.back()[1] = max(merged.back()[1], R);
}
}
return merged;
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/merge-intervals/solutions/203562/he-bing-qu-jian-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode200: 岛屿数量
LeetCode695: 岛屿的最大面积
class Solution {
public:
int count = 0;
int numIslands(vector>& grid) {
for(int i = 0; i < grid.size(); i++) {
for(int j = 0; j < grid[0].size(); j++) {
if(grid[i][j] == '1') {
count++;
dfs(grid, i, j);
}
}
}
return count;
}
void dfs(vector>& grid, int r, int c) {
//判断 base case
//如果坐标(r,c)超出了网格范围,直接返回
if(!isArea(grid, r, c)) return;
//如果这个格子不是岛屿,直接返回
if (grid[r][c] != '1') return;
grid[r][c] = 2; //将格子标记为【已遍历过】
//访问上、下、左、右四个相邻结点
dfs(grid, r-1, c);
dfs(grid, r+1, c);
dfs(grid, r, c-1);
dfs(grid, r, c+1);
}
//判断坐标(r,c)是否在网格中
bool isArea(vector>& grid, int r, int c) {
return (0 <= r && r < grid.size() && 0 <= c && c < grid[0].size());
}
};
详细题解参考如下
力扣
LeetCode40: 组合总和II
dfs的格式。
class Solution {
public:
vector> res;
vector temp;
void backtrack(vector& candidates, int target, int index)
{
if(target == 0)
{
res.push_back(temp);
return;
}
for(int i = index; i < candidates.size() && target-candidates[i] >= 0; i++)
{
if(i > index && candidates[i] == candidates[i-1])
continue;
temp.push_back(candidates[i]);
backtrack(candidates, target-candidates[i], i+1);
temp.pop_back();
}
}
vector> combinationSum2(vector& candidates, int target) {
sort(candidates.begin(), candidates.end());
backtrack(candidates, target, 0);
return res;
}
};
LeetCode93: 复原IP地址
dfs(给定变量,index=标记处理位置)
class Solution {
public:
vectorans;
void backtrace(string& s,int cnt,int index,string& str){
if(cnt==4 || index==s.size() ){
if(cnt==4 && index==s.size())
ans.push_back(str.substr(0,str.size()-1));
return;
}
for(int i=1;i<=3;i++){
if(index+i>s.size()) return;
if(s[index]=='0' && i!=1) return;
if(i==3 && s.substr(index,i)>"255") return;
str+=s.substr(index,i);
str.push_back('.');
backtrace(s,cnt+1,index+i,str);
str = str.substr(0,str.size()-i-1);
}
}
vector restoreIpAddresses(string s) {
string str ="";
backtrace(s,0,0,str);
return ans;
}
};
LeetCode90:子集II
不需要其他判断,去重操作参考LeetCode40: 组合总和II
class Solution {
private:
vector> result;
vector path;
void backtracking(vector& nums, int startIndex) {
result.push_back(path);
for (int i = startIndex; i < nums.size(); i++) {
// 而我们要对同一树层使用过的元素进行跳过
if (i > startIndex && nums[i] == nums[i - 1]) {
continue;
}
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector> subsetsWithDup(vector& nums) {
result.clear();
path.clear();
sort(nums.begin(), nums.end()); // 去重需要排序
backtracking(nums, 0);
return result;
}
};
LeetCode491: 递增子序列
此题不能排序去重。
// 版本二
class Solution {
private:
vector> result;
vector path;
void backtracking(vector& nums, int startIndex) {
if (path.size() > 1) {
result.push_back(path);
//不能return
}
int used[201] = {0}; // 这里使用数组来进行去重操作,题目说数值范围[-100, 100]
for (int i = startIndex; i < nums.size(); i++) {
if ((!path.empty() && nums[i] < path.back())
|| used[nums[i] + 100] == 1) {
continue;
}
used[nums[i] + 100] = 1; // 记录这个元素在本层用过了,本层后面不能再用了
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector> findSubsequences(vector& nums) {
result.clear();
path.clear();
backtracking(nums, 0);
return result;
}
};
作者:代码随想录
链接:https://leetcode.cn/problems/non-decreasing-subsequences/solutions/387905/491-di-zeng-zi-xu-lie-shen-sou-hui-su-xiang-jie-by/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode47: 全排列II
全排列,每次要从0开始遍历,为了跳过已入栈的元素,需要使用used。
class Solution {
public:
vector> res;
vector path;
map hash;
vector> permuteUnique(vector& nums) {
sort(nums.begin(), nums.end());
dfs(0, nums);
return res;
}
void dfs(int index, vector& nums){
if(index == nums.size()){
res.push_back(path);
return;
}
for(int i = 0; i < nums.size(); i++){ //i!=startIndex
if(hash[i] < 1){
if(i > 0 && nums[i] == nums[i-1] && hash[i-1] == 0) continue;
path.push_back(nums[i]);
hash[i]++;
dfs(index + 1, nums);
hash[i]--;
path.pop_back();
}
}
}
};
LeetCode494: 目标和
class Solution {
public:
int count = 0;
int findTargetSumWays(vector& nums, int target) {
backtrack(nums, target, 0, 0);
return count;
}
void backtrack(vector& nums, int target, int index, int sum) {
if (index == nums.size()) {
if (sum == target) {
count++;
}
} else {
backtrack(nums, target, index + 1, sum + nums[index]);
backtrack(nums, target, index + 1, sum - nums[index]);
}
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/target-sum/solutions/816361/mu-biao-he-by-leetcode-solution-o0cp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
重点是找到状态转移方程。
LeetCode53: 最大子序列和
dp[i]
:表示以 nums[i]
结尾 的 连续 子数组的最大和。
class Solution {
public:
int maxSubArray(vector& nums) {
if(nums.size()==0) return 0;
if(nums.size()==1) return nums[0];
vector dp(nums.size(),0);
dp[0] = nums[0];
int res = dp[0];
for(int i=1;ires) res=dp[i];
}
return res;
}
};
LeetCode343:整数拆分
dp[i]
:表示将正整数 i 拆分成至少两个正整数的和之后,这些正整数的最大乘积。
class Solution {
public:
int integerBreak(int n) {
vector dp(n + 1);
for (int i = 2; i <= n; i++) {
int curMax = 0;
for (int j = 1; j < i; j++) {
curMax = max(curMax, max(j * (i - j), j * dp[i - j]));
}
dp[i] = curMax;
}
return dp[n];
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/integer-break/solutions/352875/zheng-shu-chai-fen-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指offer 62: 圆圈中最后剩下的数字 == 约瑟夫环
力扣
class Solution {
public:
int lastRemaining(int n, int m) {
int x = 0;
for (int i = 2; i <= n; i++) {
x = (x + m) % i;
}
return x;
}
};
作者:Krahets
链接:https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solutions/607638/jian-zhi-offer-62-yuan-quan-zhong-zui-ho-dcow/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode63: 不同路径II
class Solution {
public:
/**
* 1. 确定dp数组下标含义 dp[i][j] 从(0,0)到(i,j)可能的路径种类;
* 2. 递推公式 dp[i][j] = dp[i-1][j] + dp[i][j-1] 但是需要加限制条件就是没有障碍物的时候
* if(obstacleGrid[i][j] == 0) dp[i][j] = dp[i-1][j] + dp[i][j-1];
* 3. 初始化 当obstacleGrid[i][j] == 0时,dp[i][0]=1 dp[0][i]=1 初始化横竖就可;
* 4. 遍历顺序 一行一行遍历;
* 5. 推导结果;
*/
int uniquePathsWithObstacles(vector>& obstacleGrid) {
/* 计算数组大小 */
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
/* 定义dp数组 */
vector> dp(m,vector(n,0));
/* 初始化dp数组 */
for(int i = 0; i < m && obstacleGrid[i][0] == 0; i++)
dp[i][0] = 1;
for(int i = 0; i < n && obstacleGrid[0][i] == 0; i++)
dp[0][i] = 1;
/* 一行一行遍历 */
for(int i = 1; i < m; i++) {
for(int j = 1; j < n; j++) {
/* 去除障碍物 */
if(obstacleGrid[i][j] == 1) continue;
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
};
滚动数组思想:
节省空间,比如dp[i] = dp[i-1]+未更新的dp[i]
class Solution {
public:
int uniquePathsWithObstacles(vector>& obstacleGrid) {
int n = obstacleGrid.size(), m = obstacleGrid.at(0).size();
vector f(m);
f[0] = (obstacleGrid[0][0] == 0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (obstacleGrid[i][j] == 1) {
f[j] = 0;
continue;
}
if (j - 1 >= 0 && obstacleGrid[i][j - 1] == 0) {
f[j] += f[j - 1];
}
}
}
return f.back();
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/unique-paths-ii/solutions/316968/bu-tong-lu-jing-ii-by-leetcode-solution-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode64: 最小路径和
class Solution {
public:
int minPathSum(vector>& grid) {
if (grid.size() == 0 || grid[0].size() == 0) {
return 0;
}
int rows = grid.size(), columns = grid[0].size();
auto dp = vector < vector > (rows, vector (columns));
dp[0][0] = grid[0][0];
// 初始化
for (int i = 1;i
LeetCode416: 分割等和子集
其中 dp[i][j] 表示从数组的 [0,i] 下标范围内选取若干个正整数(可以是 0 个),是否存在一种选取方案使得被选取的正整数的和等于 j。
class Solution {
public:
bool canPartition(vector& nums) {
int n = nums.size();
if (n < 2) {
return false;
}
int sum = accumulate(nums.begin(), nums.end(), 0);
int maxNum = *max_element(nums.begin(), nums.end());
if (sum & 1) { //数组的和必须为偶数
return false;
}
int target = sum / 2;
if (maxNum > target) { //最大值不能超过和的1/2
return false;
}
vector> dp(n, vector(target + 1, 0));
for (int i = 0; i < n; i++) {
dp[i][0] = true;
}
dp[0][nums[0]] = true;
for (int i = 1; i < n; i++) {
int num = nums[i];
for (int j = 1; j <= target; j++) {
if (j >= num) {
dp[i][j] = dp[i - 1][j] | dp[i - 1][j - num];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[n - 1][target];
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/partition-equal-subset-sum/solutions/442320/fen-ge-deng-he-zi-ji-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode322: 零钱兑换
class Solution {
public:
int coinChange(vector& coins, int amount) {
int Max = amount + 1;
vector dp(amount + 1, Max);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int j = 0; j < (int)coins.size(); ++j) {
if (coins[j] <= i) {
dp[i] = min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/coin-change/solutions/132979/322-ling-qian-dui-huan-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode518: 零钱兑换II
class Solution {
public:
int change(int amount, vector& coins) {
vector dp(amount + 1);
dp[0] = 1;
for (int& coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/coin-change-ii/solutions/821278/ling-qian-dui-huan-ii-by-leetcode-soluti-f7uh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
关于动态规划求组合数/排列数
LeetCode213: 打家劫舍II
class Solution {
public:
int rob(vector& nums) {
if (nums.empty()) return 0;
if(nums.size() == 1) return nums[0];
vector dp(nums.size()),dpp(nums.size());
for (int i = 0; i<=nums.size()-2;i++){
dp[i] = nums[i];
}
for (int i = 1; i<=nums.size()-1;i++){
dpp[i-1] = nums[i];
}
return max(myRob(dp), myRob(dpp));
}
private:
int myRob(vector nums) {
int pre = 0, cur = 0, tmp;
for(int num : nums) {
tmp = cur;
cur = max(pre + num, cur);
pre = tmp;
}
return cur;
}
};
LeetCode714: 买卖股票的最佳时机含手续费 — 这个包含了I II
class Solution {
public:
int maxProfit(vector& prices, int fee) {
//dp[i][0]:手不持股票
//dp[i][1]: 手持股票
int dp0 = 0, dp1 = -prices[0];
for( int i = 1; i < prices.size(); ++i ){
const int tdp0 = dp0, tdp1 = dp1;
dp0 = max(tdp0, tdp1+prices[i]-fee);//昨天不持,今天无交易;昨天持,今天卖。
dp1 = max(tdp1, tdp0-prices[i]);//昨天持,今天无交易;昨天不持,今天卖;
}
return dp0;
}
};
LeetCode188: 买卖股票的最佳时机IV — 这个包含了III Hard Pass
LeetCode309: 最佳买卖股票时机含冷冻期
// 思路:
// 考虑有多少种状态,每种状态有哪些选择,或者是做了哪些选择后得到哪种状态。
// 注意:到底是先选择了才有状态,还是先由状态才能选择。这里是先选择了,才有状态
// 状态类型有2种:天数和是否持有。
// 天数:一共为1-n天
// 是否持有:分为持有状态、没持有状态1、没持有状态2。
// 持有状态:选择 无处理 和 买入 都有可能达到该状态
// 没持有状态1:选择 无处理 后达到该状态。
// 没持有状态2:选择 卖出 后达到该状态。注意,卖出后进入一天的冻结期。
// 注意:这里为什么要分两种没持有状态,这是为了便于后续状态转移,如果不区分这两种状态,状态转移没法确定当天是否可以进行买入操作。
// dp表示的含义:
// dp[i][2] : 第i天为没持有状态2时,此时的最大利润
// dp[i][1] : 第i天为没持有状态1时,此时的最大利润
// dp[i][0] : 第i天为持有状态时,此时的最大利润
// 状态转移方程:
// dp[i][0]: 第i天为持有状态时,此时的最大利润
// 无处理后达到该状态: dp[i][0] = dp[i-1][0] // 第i天没有处理就持有股票,证明上一天也持有
// 买入后达到该状态: dp[i][0] = dp[i-1][1]-prices[n] // 第i天能买入股票,证明上一天没持有股票,且没进行卖出操作
// 所以dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[n]); // 这里思考个问题,两种情况都能到达这个状态的话,那如何选择?为什么是取他们的max?
// dp[i][1]: 第i天为没持有状态1时,此时的最大利润
// 无处理后达到该状态: dp[i][1] = max(dp[i-1][1], dp[i-1][2]) // 有两种到达该状态的情况,取最大那个
// dp[i][2]: 第i天为没持有状态2时,此时的最大利润
// 卖出后达到该状态: dp[i][2] = dp[i-1][0]+prices[i]
// 最后max(dp[n-1][1], dp[n-1][2])就是题目所需答案。即第n-1天没持有股票时的最大收益
// test case:
// [1,2,3,0,2]
// [1,2,-2,0,33,0,2]
// [1,2,3,0,2,3,9,0,2,4]
// [2,1]
class Solution {
public:
int maxProfit(vector& prices) {
if(prices.size() <= 1)
return 0;
int n = prices.size();
vector> dp(n, vector(3));
dp[0][0] = -prices[0];
dp[0][1] = 0;
dp[0][2] = 0; // 假设默认持有0元股票
for(int i=1; i& prices) {
if(prices.size() <= 1)
return 0;
int n = prices.size();
vector> dp(n, vector(3));
dp[0][0] = -prices[0];
dp[0][1] = 0;
dp[0][2] = 0; // 假设默认持有0元股票
for(int i=1; i
LeetCode300: 最长递增子序列
class Solution {
public:
int lengthOfLIS(vector& nums) {
int n = (int)nums.size();
if (n == 0) {
return 0;
}
vector dp(n, 0);
for (int i = 0; i < n; ++i) {
dp[i] = 1;
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/longest-increasing-subsequence/solutions/147667/zui-chang-shang-sheng-zi-xu-lie-by-leetcode-soluti/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode674:最长连续递增子序列
class Solution {
public:
int findLengthOfLCIS(vector& nums) {
/* 判断 */
if(nums.size() <= 1) return nums.size();
/* 定义记录结果的变量 */
int result = 0;
/* 定义dp数组并初始化为1 */
vector dp(nums.size() + 1, 1);
/* 遍历 */
for(int i = 1; i < nums.size(); i++) {
if(nums[i-1] < nums[i]) {
/* 不连续递增子序列的跟前0-i 个状态有关,连续递增的子序列只跟前一个状态有关 */
dp[i] = dp[i-1] + 1;
}
/* 记录dp数组中的最大值 */
if(result < dp[i]) result = dp[i];
}
return result;
}
};
作者:Gnakuw
链接:https://leetcode.cn/problems/longest-continuous-increasing-subsequence/solutions/1297309/zui-chang-lian-xu-di-zeng-xu-lie-by-kino-on97/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。