今天主要刷了三个力扣题目,顺便记录一下昨天刷的
这几个题目还挺超出我能力范围的
1.最长增长子序列
参考:
https://leetcode.cn/problems/longest-increasing-subsequence/solutions/24173/zui-chang-shang-sheng-zi-xu-lie-dong-tai-gui-hua-2/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj
第一种方法就是两次循环遍历
核心思想是dp
class Solution {
public int lengthOfLIS(int[] nums) {
int len = nums.length;
int[] dp = new int[len];
int max = 1;
Arrays.fill(dp,1);
for (int i = 1; i < len; i++) {
//看看前面比i小的数里面累计长度最大的 +1
for (int j = 0; j < i; j++) {
if(nums[i] > nums[j]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
max = Math.max(max,dp[i]);
}
return max;
}
}
第二种方法有点类似于贪心
保存的数据比较特殊
数组record记录的分别为长度为1时最小的的数字 长度为2 时最小的数字 长度为n时最小的数字
从左向右遍历
如果大于长度为1的数字 那么这个字符串最小就是2了, 就像后遍历 如果小于这个数字 说明长度为1的数字 还能更小 更有利于让未来更长
public int lengthOfLIS(int[] nums) {
int len = nums.length;
int[] record = new int[len];
record[0] =nums[0];
int max = 1;
for (int i = 1; i < len; i++) {
boolean temp = true;
for (int j = 0; j < max; j++) {
if(nums[i] <= record[j]){
record[j] = nums[i];
temp = false;
break;
}
}
if(temp){
max++;
record[max-1]=nums[i];
}
}
return max;
}
2.删除无效括号
参考:https://leetcode.cn/problems/remove-invalid-parentheses/solutions/1068652/gong-shui-san-xie-jiang-gua-hao-de-shi-f-asu8/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj
这个主要涉及到以下几个问题
1.最少删除几个左括号 和 右括号?
for(char c:s.toCharArray()){
if(c=='('){
l++;
}else if(c==')'){
if(l != 0) l--;
else r++;
}
}
2.在回溯过程中 右括号数目不能超过左括号数目 可以进行剪枝
当然左括号数目也不能超过最大的max
代码如下
class Solution {
Set<String> set = new HashSet<>();
int n, max, len;
String s;
public List<String> removeInvalidParentheses(String _s) {
s = _s;
n = s.length();
int l = 0, r = 0;
//真正合理的方式去计算削减左括号和右括号的数量
for(char c:s.toCharArray()){
if(c=='('){
l++;
}else if(c==')'){
if(l != 0) l--;
else r++;
}
}
//最终的长度
len = n-l-r;
//这里的目的是剪枝 value值不能小于0 不能大于max=min(c1,c2)
int c1 = 0, c2 = 0;
for(char c : s.toCharArray()){
if(c == '(') c1++;
else if(c==')') c2++;
}
max = Math.min(c1,c2);
//第一个参数是遍历原字符串字符的位置
//第二个参数是组成的新字符串
//第三个和第四个是应该删除的左右字符数
//第五个参数是value
dfs(0,"",l,r,0);
return new ArrayList<>(set);
}
void dfs(int u,String cur, int l, int r, int score){
if(l < 0||r<0||score<0||score>max) return;
if(l==0 && r== 0){
if(cur.length() == len) set.add(cur);
}
if(u == n) return;
char c = s.charAt(u);
if(c == '('){
dfs(u+1,cur+String.valueOf(c), l, r, score+1);
dfs(u+1,cur, l -1,r,score);
}else if(c == ')'){
dfs(u+1,cur+String.valueOf(c), l, r, score-1);
dfs(u+1, cur ,l, r-1, score);
}else{
dfs(u+1, cur + String.valueOf(c),l,r,score);
}
}
}
3.买卖股票的最佳时机含冷冻期
这类问题都是通过状态向量机递得到的dp递推式
主要参考:https://www.bilibili.com/video/BV1ho4y1W7QK/?spm_id_from=333.337.search-card.all.click&vd_source=b81ab5eddf51d16c41cb0a31aeb9241a
dp主要维护两个状态 持有股票和未持有股票 max一定是未持有股票的
冷冻期主要体现在dp时 持有股票状态只能来源于前面隔一天的未持有股票状态
代码如下:
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][] dp = new int[len+2][2];
dp[1][1] = Integer.MIN_VALUE;
for (int i = 0; i < len; i++) {
dp[i+2][0] = Math.max(dp[i+1][0],dp[i+1][1] + prices[i]);
dp[i+2][1] = Math.max(dp[i+1][1],dp[i][0] - prices[i]);
}
return dp[len+1][0];
}
}
4.戳气球
也是一个dp问题
首先转化问题为戳 i 到 j 之间的气球的最大值 不包括i j
那么就可以遍历 i 到j 设定为 k
dp[i][j]就是所有 dp[i][k]+dp[k][j]+score[i]*score[j]*score[k]里面的最大值
score是对nums的扩展了头1 和 尾1
代码为
public int maxCoins(int[] nums) {
int len = nums.length;
int[] score = new int[len+2];
score[0] = score[len+1] = 1;
for (int i = 0; i < len; i++) {
score[i+1] = nums[i];
}
int[][] dp = new int[len+2][len+2];
for (int i = len; i >= 0 ; i--) {
for (int j = i+1; j < len + 2; j++) {
for (int k = i+1; k < j ; k++) {
dp[i][j] = Math.max(dp[i][j],dp[i][k] + dp[k][j] + score[i]*score[j]*score[k]);
}
}
}
return dp[0][len+1];
}