1.最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
动态规划,状态转移方程:dp[i] = max{A[i], dp[i-1]+A[i]}
public static int maxSubArray(int[] nums) {
if (nums == null)
return 0;
int len = nums.length;
int max = nums[0];
int[] dp = new int[len];
dp[0] = nums[0];
for (int i = 1; i < len; i++) {
if (dp[i - 1] > 0)
dp[i] = dp[i - 1] + nums[i];
else
dp[i] = nums[i];
}
for (int i = 0; i < len; i++) {
if (max < dp[i])
max = dp[i];
}
return max;
}
不借助dp数组:
一定先判断 if(max<sum)后 if(sum<0);
因为如果全负数的情况,sum=0;会影响导致结果为0;
public int maxSubArray(int[] nums) {
if (nums == null)
return 0;
int len = nums.length;
int max = nums[0];
int sum = 0;
for(int i=0;i<len;i++) {
sum=sum+nums[i];
if(max<sum)
max=sum;
if(sum<0)
sum=0;
}
return max;
}
2.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1 阶 + 1 阶
2 阶
思路:跳台阶问题
public int climbStairs(int n) {
if (n <= 0)
return 0;
if (n < 3)
return n;
int f1 = 1, f2 = 2, res = 0;
for (int i = 3; i <= n; i++) {
res = f1 + f2;
f1 = f2;
f2 = res;
}
return res;
}
300.最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
思路:动态规划dp[i] 存储的是以i为最后元素的,最长子序列长度;
因此需要内循环j从0遍历到i,如果存在比nums[i]小的元素,则计算dp转移方程;
dp[i]= max(dp[i], dp[j] + 1);
注意:此类题是O(N2),上升子序列不是连续的;
public int lengthOfLIS(int[] nums) {
if(nums==null)
return 0;
int len = nums.length;
int[] dp=new int[len];
for(int i=0;i<len;i++){
dp[i]=1;
}
int res = 0;
for(int i=0;i<len;i++) {
for(int j=0;j<i;j++) {
if(nums[i]>nums[j])
dp[i]=dp[i]>dp[j]+1?dp[i]:dp[j]+1;
}
res=res>dp[i]?res:dp[i];
}
return res;
}
674.最长连续递增序列
给定一个未经排序的整数数组,找到最长且连续的的递增序列。
示例 1:
输入: [1,3,5,4,7]
输出: 3
解释: 最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开。
思路:设计数器count,如果遇到更大的数,则加一;否则,计数器归一;
res始终保存当前最大count值;
public static int findLengthOfLCIS(int[] nums) {
if(nums==null)
return 0;
int res=1;
int len = nums.length;
int cur=nums[0];
int count=1;
for(int i=1;i<len;i++) {
if(nums[i]>cur)
count++;
else
count=1;
res=res>count?res:count;
cur=nums[i];
}
return res;
}
最长公共子序列LCS
链接:https://www.nowcoder.com/questionTerminal/c996bbb77dd447d681ec6907ccfb488a
来源:牛客网
对于两个字符串,请设计一个高效算法,求他们的最长公共子序列的长度,这里的最长公共子序列定义为有两个序列U1,U2,U3…Un和V1,V2,V3…Vn,其中Ui<Ui+1,Vi<Vi+1。且A[Ui] == B[Vi]。
给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300。
测试样例:
“1A2C3D4B56”,10,“B1D23CA45B6A”,12
返回:6
思路:
动态规划;dp[i][j]表示A字符串的前i字符与B串的前j字符的最长公共子序列的长度;
转移方程:当A[i]==B[j],dp[i][j]=dp[i-1][j-1]+1;
否则dp[i][j]=max{dp[i-1][j],dp[i][j-1]};
注意:子序列问题同子串问题区分;子串是连续的;
public static int findLCS(String A, int n, String B, int m) {
int[][] dp = new int[n + 1][m + 1];
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (A.charAt(i - 1) == B.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[n][m];
}
最长公共连续子串
输入
abcde
abgde
输出
2
思路:与上题类似,动态规划思想;
主要区别是,dp矩阵意义为A串以i结尾与B串以j结尾的最长公共连续子串;
当A[i-1] = B[j-1]时,dp[i][j] = dp[i -1][j -1] + 1;
A[i-1] != B[j-1]时,以他们结尾的公共子串长度必然为0;
最后从dp中取出长度最大的值即为最长公共子串;
public static int findLongest(String A, int n, String B, int m) {
int [][]dp=new int[n+1][m+1];
int max=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if (A.charAt(i - 1) == B.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j]=0;
max=Math.max(max, dp[i][j]);
}
}
return max;
}
买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
思路:遍历数组;
res保存当前最小的值;
max保存当前收益最大的值;
因为如果出现了比当前res小的数,买入更小的res以后序的相同价格卖出,一定比之前的收益高,所有直接替换保证res为当前最小值即可;
public int maxProfit(int[] prices) {
if(prices==null||prices.length==0)
return 0;
int len = prices.length;
int max=0;
int res = Integer.MAX_VALUE;
for(int i=0;i<len;i++) {
res = Math.min(prices[i], res);
max = Math.max(max, prices[i]-res);
}
return max;
}
买卖股票的最佳时机 II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
思路:只需遍历数组;如果当前元素比前个元素大,即加入收益;
因为如果后序仍有比当前元素大的元素,再以当前价格买入,后序价格卖出即可,不会丢失任何利润;
public int maxProfit(int[] prices) {
if(prices==null||prices.length==0)
return 0;
int len = prices.length;
int res =0;
for(int i=1;i<len;i++) {
if(prices[i]>prices[i-1])
res+=prices[i]-prices[i-1];
}
return res;
}