继续补作业~~~
72. 编辑距离
给你两个单词 word1
和 word2
, 请返回将 word1
转换成 word2
所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
核心思路:还是一道经典的动态规划问题,需要明确的是dp数组含义以i-1字符为结尾的word1和以j-1结尾的字符word2替换成功所使用的最小操作数为dp[i][j]
明确递推公式,存在两种情况
情况一:两个字符相等,相等就不需要进行操作,也就是继承上一个状态就ok
情况二:两个字符不相等,不相等我们需要执行插入,删除,或者替换,删除一个字符有可能操作的是word1也有可能是word2,所以此时的 dp[i][j]有可能是dp[i][j-1]也有可能是dp[i-1][j],并且删除字符之后操作数需要加1,其实插入也是变相的删除,所以合并为一个
之后需要讨论替换的状态,明确替换之后操作数加一,并且替换之后两个字符相等,也就是达到状态dp[i-1][j-1]如此 递推公式就确定了,之后初始化的时候根据含义第一行第一列依旧和字符数量相等。
完整代码如下
class Solution {
public int minDistance(String word1, String word2) {
//使用动态规划解决
//1,确定dp、数组
//dp[i][j]代表以i-1结尾的word1和以j-1结尾的word2相同时的最小操作数
int len1=word1.length();
int len2=word2.length();
int[][] dp=new int[len1+1][len2+1];
//2,确定递推公式
//对于本题目来说,我们需要考虑两种情况,一种是两个字符相等,一种是不相等
//当两个字符相等的时候,不需要操作所以dp[i][j]=dp[i-1][j-1]
//当两个字符不相等,有三种操作方式,插入,删除,替换
//1,删除
//删除一个字符之后操作数加1,可能删除word1也可能word2,对应
//dp[i][j]=dp[i-1][j]+1
//dp[i][j]=dp[i][j-1]+1
//2,插入
//其实插入的逻辑就是反向的删除,所以 不需要格外考虑
//3,替换
//替换一个之后两个字符就可以达到相等的状态,并且此时操作数需要加1
//dp[i][j]=dp[i-1][j-1]+1
//初始化
for(int i=0;i<=len1;i++) dp[i][0]=i;
for(int j=0;j<=len2;j++) dp[0][j]=j;
//遍历
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]=Math.min(dp[i-1][j-1]+1,
Math.min(dp[i-1][j]+1,dp[i][j-1]+1));
}
}
}
return dp[len1][len2];
}
}
647. 回文子串
给你一个字符串 s
,请你统计并返回这个字符串中 回文子串 的数目。
回文字符串 是正着读和倒过来读一样的字符串。
子字符串 是字符串中的由连续字符组成的一个序列。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
整体思路:依旧使用动态规划的思路,虽然本题判断的是一个字符串以及子串,但是我们使用二位dp数组 dp[i][j]代表的是在区间 [i,j]的字符是否是回文子串,我们dp数组并不记录数量,为了后续推导我们定义为一个boolean类型的数组
这时候需要推导递推公式,其实也是两种情况
情况一:两个字符相等
如果两个字符相等其实有三种情况第一种类似于 a 只有一个字符,第二种 aa 两个字符,这两种都可以归为一类,不影响,但是还有一种情况类似于 a***a你并不知道中间的情况,所以就需要进行对中间是否是会问的判断,如果是会文串,个数加一,如果不是不需要讨论。
完整代码如下:
class Solution {
public int countSubstrings(String s) {
//动态规划
//1,dp数组含义
//dp[i][j]表示在全范围内[i.j]的子串是否是回文子串
int len=s.length();
boolean[][] dp=new boolean[len][len];
//2,确定递推公式
//当两个字符相等的时候,有三种情况
//1,i=j,直观表达 a
//2 aa
//3, a***a
//对于这三种情况,只有第三种需要关心[i-1,j-1]是否相等
//3,初始化,默认为false
//4,遍历顺序,因为dp[i][j]可能是由dp[i+1][j-1]推导而来,
//所以应该从下往上,从左往右
int res=0;
for(int i=len-1;i>=0;i--){
for(int j=i;j
516. 最长回文子序列
给你一个字符串 s
,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入:s = "bbbab" 输出:4 解释:一个可能的最长回文子序列为 "bbbb"
解题思路:这道题的思路和上一道差不多,主要是最长序列的定义是可以不连续,所以讨论的时候需要注意这种情况
首先确定dp数组含义此时的dp数组含义就是区间[i,j]对应的字符的最长回文子串的最大长度,确定递推公式,也存在两种情况,一种是两个字符相等很自然的回文串长度加2,问题是如果相等,则存在两种情况,一种是取左边字符的转态,另一种是右边字符状态,最后比较,其实这里我个人认为是比较抽象的,后续再思考思考
完整代码:
class Solution {
public int longestPalindromeSubseq(String s) {
//动态规划
//1,确定dp数组含义
//dp[i][j] 字符串在[i,j]范围内的最长回文子序列为dp[i][j]
int len=s.length();
int[][] dp=new int[len][len];
//2,确定递推公式
//情况一,当两个字符相等的时候,子串的长度应该加2
//dp[i][j]=dp[i-1][j-1]+2;
//情况二,两个字符不相等的时候,说明同时加入并不能增加区间回文子串的长度
//于是,尝试分别加入
//dp[i][j]=max(dp[i][j-1],dp[i+1][j])
//3,dp数组初始化
//当两个字符相等的时候回文子串为1
for(int i=0;i=0;i--){
for(int j=i+1;j
739. 每日温度
给定一个整数数组 temperatures
,表示每天的温度,返回一个数组 answer
,其中 answer[i]
是指对于第 i
天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0
来代替。
示例 1:
输入: temperatures
= [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]j
解题思路:其实一开始我是使用暴力算法求解了,但是不出意外的是超时了,分析了超时愿意就是重复的遍历已经遍历过的元素
于是使用单调栈来处理这个问题,思路想明白了,直接上代码:
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
//使用暴力解法超时,接下来使用单调栈解决
//单调栈顾名思义是存放的单调元素,在本题中,我们存放便利过的数组
//的下表,这样在下一次便利的时候就不需要在进行额外的遍历
int len=temperatures.length;
int[] res=new int[len];
Deque stack=new LinkedList();
stack.push(0);//现将第一个元素入栈
for(int i=1;itemperatures[stack.peek()]){
res[stack.peek()]=i-stack.peek();
stack.pop();
}
stack.push(i);
}
}
return res;
}
//暴力解法,超时了
public int[] baoli(int[] temperatures){
//双重for循环解决,思路没问题,但是超时了,潮湿的原因就是
//已经计算过的下标被重复的计算,例如上一次我从1开始计算到了下表7,这一次
//我继续从2开始,2~7
int len=temperatures.length;
int[] index=new int[len];
a:for(int i=0;itemperatures[i]){
res++;
index[i]=res;
break b;//结束第二层也就是for循环b
}else{
res++;
}
}
}
return index;
}
}
By-三条直线围墙