标签:数组、动态规划
思路:1.一个变量记录前面扫描过的最小值,一个变量记录目前交易中最大的收益金额。
从头至尾扫描一遍数组,如果当前的值 < 已扫描过的最小值,更新最小值;收益 = Math.max(maxProfit,prices[i] - minPrice);
代码:
public int maxProfit(int[] prices) {
int minPrice = prices[0];
int maxProfit = 0;
for(int i = 1;i < prices.length;i++){
if(prices[i] < minPrice){
minPrice = prices[i];
}
maxProfit = Math.max(maxProfit,prices[i] - minPrice);
}
return maxProfit;
}
思路2:动态规划解法
dp[i][j]表示第i天买入,第j天卖出的利润。
2._72_编辑距离
标签:动态规划
思路:设字符串s1长度为n1,字符串s2长度为n2,设置一个dp[n1+1][n2+1]数组。
dp[i][j]是s1[0,i)转化成s2[0,j)的最少操作数。
初始状态:dp[0][0] = 0;
dp[0,i]表示s1空串转换成s2[0,i)的最少操作数,即s2的长度
dp[i,0]表示s1[0,i)转换成s2空串的最少操作数,即s2的长度
将一个字符串转换成另一个字符串共有三种操作(删除、添加、替换),dp[i][j]可能有以下情况:
1)dp[i][j] = dp[i - 1][j] +1;
2)dp[i][j] = dp[i][j - 1] + 1;
3) 若s1[i - 1] = s2[j - 1]: dp[i][j] = dp[i-1][j-1]
s1[i - 1] != s2[j - 1] :dp[i][j] = dp[i-1][j-1] + 1;
代码:
public int minDistance(String word1, String word2) {
char[] s1 = word1.toCharArray();
char[] s2 = word2.toCharArray();
int[][] dp = new int[s1.length + 1][s2.length + 1];
dp[0][0] = 0;
for(int i = 1;i <= s1.length;i++){
dp[i][0] = i;
}
for(int j = 1;j <= s2.length;j++){
dp[0][j] = j;
}
for(int i = 1;i <= s1.length;i++){
for(int j = 1;j <= s2.length;j++){
int top = dp[i - 1][j] + 1;
int left = dp[i][j - 1] + 1;
int leftTop;
if(s1[i - 1] == s2[j - 1]){
leftTop = dp[i - 1][j - 1] ;
}else{
leftTop = dp[i - 1][j - 1] + 1;
}
dp[i][j] = Math.min(Math.min(top,left),leftTop);
}
}
return dp[s1.length][s2.length];
}
标签:字符串、动态规划
思路1:采用动态规划的思想,设置dp数组,dp[i][j]表示s[i][j]是否为回文串,dp数组存储true或false;
分两种情况讨论:
1)s[i,j]的长度 <=2,即s[i,i]或是s[i,i+1]这种情况,如果s[i]==s[j],那么s[i,j]是回文串,dp[i][j] = true;
2) s[i][j]的长度 > 2,如果s[i+1,j-1]是回文串,且s[i] == s[j] ,dp[i][j]才为true.
在存储true时,需要记录回文子串长度的最大值,且需要记录最大值的起始索引。
代码:
public String longestPalindrome(String s) {
char[] cs = s.toCharArray();
boolean[][] dp = new boolean[cs.length][cs.length];
int maxLength = 1;
int begin = 0;
for(int i = cs.length - 1;i >= 0 ;i--){
for(int j = i;j < cs.length;j++){
int len = j - i + 1;
dp[i][j] = (cs[i] == cs[j] && (len <= 2 || dp[i +1][j - 1]));
if(dp[i][j] && len > maxLength){
maxLength = len;
begin = i;
}
}
}
return s.substring(begin,begin + maxLength);
}
时间复杂度:O(n²) 空间复杂度 :O(n²)
思路2:扩展中心法
以每个字符或每个间隙为中心,向左右扩展。
代码:
public String longestPalindromeEX(String s) {
char[] cs = s.toCharArray();
if(cs.length <= 1) return s;
int maxLength = 1;
// 最长回文子串的开始索引
int begin = 0;
for(int i = cs.length - 2;i >= 1;i--){
// 以字符为中心向左右扩展
int len1 = palindromeLength(cs,i -1,i + 1);
// 以字符右边的间隙为中心向左右扩展
int len2 = palindromeLength(cs,i,i + 1);
len1 = Math.max(len1,len2);
if(len1 > maxLength){
maxLength = len1;
begin = i - ((maxLength -1) >> 1);
}
}
// 以0号字符右边的间隙为中心的最长回文子长度是2
if(cs[0] == cs[1] && maxLength < 2){
maxLength = 2;
begin = 0;
}
return s.substring(begin,begin + maxLength);
}
/**
* 只需传入左开始索引和右开始索引,向左向右延申。
*/
private int palindromeLength(char[] cs,int l,int r){
while(l >= 0 && r < cs.length && cs[l] == cs[r]){
l--;
r++;
}
return r - l - 1;
}
时间复杂度:O(n²) 空间复杂度 :O(1 )
扩展中心法的优化:
思路:
代码:
public String longestPalindromeEX_B(String s) {
char[] cs = s.toCharArray();
if(cs.length <= 1) return s;
int maxLength = 1;
// 最长回文子串的开始索引
int begin = 0;
int i = 0;
while(i < cs.length ){
int l = i - 1;
int r = i;
//找到右边第一个不等于cs[i]的位置
while(++r < cs.length && cs[r] == cs[i]);
//r作为下一次的i
i = r;
//从l向左,从r向右扩展
while(l >= 0 && r < cs.length && cs[l]==cs[r]){
l--;
r++;
}
//扩展结束后,cs[l + 1,r)就是找到的最大回文子串
//++l后是找到的最大回文子串的开始索引
int len = r - ++l;
if(len > maxLength){
maxLength = len;
begin = l;
}
}
return s.substring(begin,begin + maxLength);
}