买卖股票的最好时机(一)
java
public int maxProfit (int[] prices) {
int min = prices[0];
int max = 0;
for(int i=0;i<prices.length;i++){
min=Math.min(prices[i],min);
max=Math.max(max,prices[i]-min);
}
return max;
}
买卖股票的最好时机(二)
java
public int maxProfit(int[] prices) {
if (prices == null || prices.length < 2)
return 0;
int length = prices.length;
//初始条件
int hold = -prices[0]; //持有股票
int noHold = 0; //没持股票
for (int i = 1; i < length; i++) {
//递推公式转化的
noHold = Math.max(noHold, hold + prices[i]);
hold = Math.max(hold, noHold - prices[i]);
}
//最后一天肯定是手里没有股票的时候利润才会最大,
//所以这里返回的是noHold
return noHold;
}
买卖股票的最好时机(三)
最多可以买入卖出2次,那实际上相当于它的状态多了几个,对于每天有到此为止的最大收益和持股情况两个状态,持股情况有了5种变化,我们用:
dp[i][0]表示到第i天为止没有买过股票的最大收益
dp[i][1]表示到第i天为止买过一次股票还没有卖出的最大收益
dp[i][2]表示到第i天为止买过一次也卖出过一次股票的最大收益
dp[i][3]表示到第i天为止买过两次只卖出过一次股票的最大收益
dp[i][4]表示到第i天为止买过两次同时也买出过两次股票的最大收益
java
import java.util.*;
public class Solution {
public int maxProfit (int[] prices) {
int n = prices.length;
int[][] dp = new int[n][5];
//初始化dp为最小
Arrays.fill(dp[0], -10000);
//第0天不持有状态
dp[0][0] = 0;
//第0天持有股票
dp[0][1] = -prices[0];
//状态转移
for(int i = 1; i < n; i++){
dp[i][0] = dp[i - 1][0];
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
//选取最大值,可以只操作一次
return Math.max(dp[n - 1][2],Math.max(0, dp[n - 1][4]));
}
}
分糖果问题
java
public int candy (int[] arr) {
int n=arr.length;
if(n<=1)
return n;
int[] nums = new int[n];
//初始化
for(int i = 0; i < n; i++)
nums[i] = 1;
//从左到右遍历
for(int i = 1; i < arr.length; i++){
//如果右边在递增,每次增加一个
if(arr[i] > arr[i - 1])
nums[i] = nums[i - 1] + 1;
}
//记录总糖果数
int res = nums[arr.length - 1];
//从右到左遍历
for(int i = arr.length - 2; i >= 0; i--){
//如果左边更大但是糖果数更小
if(arr[i] > arr[i + 1] && nums[i] <= nums[i + 1])
nums[i] = nums[i + 1] + 1;
//累加和
res += nums[i];
}
return res;
}
主持人调度(二)
java
import java.util.*;
public class Solution {
public int minmumNumberOfHost (int n, int[][] startEnd) {
int[] start = new int[n];
int[] end = new int[n];
//分别得到活动起始时间
for(int i = 0; i < n; i++){
start[i] = startEnd[i][0];
end[i] = startEnd[i][1];
}
//单独排序
Arrays.sort(start, 0, start.length);
Arrays.sort(end, 0, end.length);
int res = 0;
int j = 0;
for(int i = 0; i < n; i++){
//新开始的节目大于上一轮结束的时间,主持人不变
if(start[i] >= end[j])
j++;
else
//主持人增加
res++;
}
return res;
}
}
矩阵的最小路径和
java
public int minPathSum (int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
int dp[][] = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (i == 0 && j == 0) {
dp[0][0] = matrix[0][0];
} else if (i == 0) {
//第一行只能从左边走过来
dp[i][j] = matrix[i][j] + dp[i][j - 1];
} else if (j == 0) {
//第一列只能从上面走下来
dp[i][j] = matrix[i][j] + dp[i - 1][j];
} else {
//递推公式,取从上面走下来和从左边走过来的最小值+当前坐标的值
dp[i][j] = matrix[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m - 1][n - 1];
}
把数字翻译成字符串(二)
java
import java.util.*;
public class Solution {
public int solve (String nums) {
//排除0
if (nums.equals("0"))
return 0;
//排除只有一种可能的10 和 20
if (nums == "10" || nums == "20")
return 1;
//当0的前面不是1或2时,无法译码,0种
for (int i = 1; i < nums.length(); i++) {
if (nums.charAt(i) == '0')
if (nums.charAt(i - 1) != '1' && nums.charAt(i - 1) != '2')
return 0;
}
int[] dp = new int[nums.length() + 1];
//辅助数组初始化为1
Arrays.fill(dp, 1);
for (int i = 2; i <= nums.length(); i++) {
//在11-19,21-26之间的情况
if ((nums.charAt(i - 2) == '1' && nums.charAt(i - 1) != '0') ||
(nums.charAt(i - 2) == '2' && nums.charAt(i - 1) > '0' && nums.charAt(i - 1) < '7'))
dp[i] = dp[i - 1] + dp[i - 2];
else
dp[i] = dp[i - 1];
}
return dp[nums.length()];
}
}
兑换零钱(一)
java
import java.util.*;
public class Solution {
public int minMoney (int[] arr, int aim) {
//小于1的都返回0
if (aim < 1) return 0;
int[] dp = new int[aim + 1];
//dp[i]表示凑齐i元最少需要多少货币数
Arrays.fill(dp, aim + 1);
dp[0] = 0;
//遍历1-aim元
for (int i = 1; i <= aim; i++) {
//每种面值的货币都要枚举
for (int j = 0; j < arr.length; j++) {
//如果面值不超过要凑的钱才能用
if (arr[j] <= i)
//维护最小值
dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1);
}
}
//如果最终答案大于aim代表无解
return dp[aim] > aim ? -1 : dp[aim];
}
}
最长公共子序列(二)
java
public static String LCS(String s1, String s2) {
int row = s1.length();
int column = s2.length();
// `dp[i][j]`表示从左到右,当处理到s1的第i个元素和s2的第j个元素时的公共子序列长度
// 默认初始化为0,因此base case的 i == 0 和 j == 0 的情况不需要手动初始化
int[][] dp = new int[row + 1][column + 1];
// 状态转移
for (int i = 1; i < row + 1; i++) {
for (int j = 1; j < column + 1; j++) {
// 字符相等,则通过前一个状态+1获得当前状态
if (s1.charAt(i - 1) == s2.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]);
}
}
}
//目前dp记录了s1和s2的最长子序列的长度
if (dp[row][column] == 0)
return "-1";
// lcs用来储存结果数组
char[] lcs = new char[dp[row][column]];
// 因为要对dp倒着查看,所以lcs也倒着插入,cur表示当前插入的位置
int cur = lcs.length - 1;
// 通过双指针,遍历s1和s2字符串
while (true) {
// 相等则添加结果,两个指针左移
if (s1.charAt(row - 1) == s2.charAt(column - 1)) {
//记录字符
lcs[cur--] = s1.charAt(row - 1);
if (cur < 0) {
return new String(lcs);
}
row--;
column--;
} else {
// 不相等,则根据dp保存的状态,进行指针移动
if (dp[row - 1][column] > dp[row][column - 1]) {
// 忽略掉s1[row-1]
row--;
} else {
// 忽略掉s2[column-1]
column--;
}
}
}
}
二分查找-I
java
public int search (int[] nums, int target) {
int l = 0;
int r = nums.length - 1;
//从数组首尾开始,直到二者相遇
while(l <= r){
//每次检查中点的值
int m = (l + r) / 2;
if(nums[m] == target)
return m;
//进入左的区间
if(nums[m] > target)
r = m - 1;
//进入右区间
else
l = m + 1;
}
//未找到
return -1;
}
二维数组中的查找
(1)从左下角找
java
public boolean Find(int target, int [][] array) {
int rows = array.length;
if(rows == 0){
return false;
}
int cols = array[0].length;
if(cols == 0){
return false;
}
// 左下
int row = rows-1;
int col = 0;
while(row>=0 && col<cols){
if(array[row][col] < target){
col++;
}else if(array[row][col] > target){
row--;
}else{
return true;
}
}
return false;
}
(2)从右上角找
java
public boolean Find(int target, int [][] array) {
int rows = array.length;
if(rows == 0){
return false;
}
int cols = array[0].length;
if(cols == 0){
return false;
}
// 右上
int row = 0; //注意
int col = cols-1; //注意
while(row<rows && col>=0){ //注意
if(array[row][col] < target){
row++; //注意
}else if(array[row][col] > target){
col--; //注意
}else{
return true;
}
}
return false;
}
寻找峰值
java
public int findPeakElement (int[] nums) {
int left = 0;
int right = nums.length - 1;
//二分法
while(left < right){
int mid = (left + right) / 2;
//右边是往下,不一定有坡峰
if(nums[mid] > nums[mid + 1])
right = mid;
//右边是往上,一定能找到波峰
else
left = mid + 1;
}
return right;
}
数组中的逆序对
java
public class Solution {
public int mod = 1000000007;
public int mergeSort(int left, int right, int [] data, int [] temp){
//停止划分
if(left >= right)
return 0;
//取中间
int mid = (left + right) / 2;
//左右划分合并
int res = mergeSort(left, mid, data, temp) + mergeSort(mid + 1, right, data, temp);
//防止溢出
res %= mod;
int i = left, j = mid + 1;
for(int k = left; k <= right; k++)
temp[k] = data[k];
for(int k = left; k <= right; k++){
if(i == mid + 1)
data[k] = temp[j++];
else if(j == right + 1 || temp[i] <= temp[j])
data[k] = temp[i++];
//左边比右边大,答案增加
else{
data[k] = temp[j++];
// 统计逆序对
res += mid - i + 1;
}
}
return res % mod;
}
public int InversePairs(int [] array) {
int n = array.length;
int[] res = new int[n];
return mergeSort(0, n - 1, array, res);
}
}
旋转数组
java
public class Solution {
public int[] solve (int n, int m, int[] a) {
//取余,因为每次长度为n的旋转数组相当于没有变化
m = m % n;
//第一次逆转全部数组元素
reverse(a, 0, n - 1);
//第二次只逆转开头m个
reverse(a, 0, m - 1);
//第三次只逆转结尾m个
reverse(a, m, n - 1);
return a;
}
//反转函数
public void reverse(int[] nums, int start, int end){
while(start < end){
swap(nums, start++, end--);
}
}
//交换函数
public void swap(int[] nums, int a, int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
旋转数组的最小数字
(1)二分法
java
public int minNumberInRotateArray(int [] array) {
int left = 0;
int right = array.length - 1;
while(left < right){
int mid = (left + right) / 2;
//最小的数字在mid右边
if(array[mid] > array[right])
left = mid + 1;
//无法判断,一个一个试
else if(array[mid] == array[right])
right--;
//最小数字要么是mid要么在mid左边
else
right = mid;
}
return array[left];
}
(2)遍历查找
java
public int minNumberInRotateArray(int [] array) {
//数组一定有元素
int res = array[0];
//遍历数组
for(int i = 1; i < array.length; i++) {
//每次维护最小值
res = Math.min(res, array[i]);
}
return res;
}
比较版本号
java
public int compare(String version1, String version2) {
String s1[] = version1.split("\\.");
String s2[] = version2.split("\\.");
int n1 = s1.length;
int n2 = s2.length;
int n = Math.max(n1, n2);
int k1[] = new int[n];
for (int i = 0; i < s1.length; i++) {
k1[i] = Integer.valueOf(s1[i]);
}
int k2[] = new int[n];
for (int i = 0; i < s2.length; i++) {
k2[i] = Integer.valueOf(s2[i]);
}
for (int i = 0; i < n; i++) {
if (k1[i] > k2[i]) {
return 1;
} else if (k1[i] < k2[i]) {
return -1;
}
}
return 0;
}
螺旋矩阵
java
public ArrayList<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
if(matrix.length == 0) {
return list;
}
int left = 0;
int right = matrix[0].length - 1;
int top = 0;
int bottom = matrix.length - 1;
int x = 0;
while(true) {
for(int i = left; i <= right; i++) { //从左到右
list.add(matrix[top][i]) ;
}
if(++top > bottom){
break;
}
for(int i = top; i <= bottom; i++){
list.add( matrix[i][right]); //从上到下
}
if(left > --right){
break;
}
for(int i = right; i >= left; i--){
list.add(matrix[bottom][i]); //从右到左
}
if(top > --bottom){
break;
}
for(int i = bottom; i >= top; i--){
list.add(matrix[i][left]); //从下到上
}
if(++left > right){
break;
}
}
return list;
}
顺时针旋转矩阵
(1) 矩阵转置
java
import java.util.*;
public class Solution {
public int[][] rotateMatrix(int[][] mat, int n) {
int length = mat.length;
//矩阵转置
for(int i = 0; i < length; ++i){
for(int j = 0; j < i; ++j){
//交换上三角与下三角对应的元素
int temp = mat[i][j];
mat[i][j] = mat[j][i];
mat[j][i] = temp;
}
}
//每行翻转
for (int i = 0; i < length; i++) {
for (int j = 0; j < length/2; j++){
int temp = mat[i][j];
mat[i][j] = mat[i][length - j - 1];
mat[i][length - j - 1] = temp;
}
}
return mat;
}
}
(2)先上下交换,在对角线交换
java
public int[][] rotateMatrix(int[][] matrix, int n) {
int length = matrix.length;
//先上下交换
for (int i = 0; i < length / 2; i++) {
int temp[] = matrix[i];
matrix[i] = matrix[length - i - 1];
matrix[length - i - 1] = temp;
}
//在按照对角线交换
for (int i = 0; i < length; ++i) {
for (int j = i + 1; j < length; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
return matrix;
}