LeetCode动态规划题目和相关测试

This commit is contained in:
whaifree 2024-04-12 22:50:16 +08:00
parent 0ec6ab1e6c
commit 0cbd5b4619
5 changed files with 512 additions and 0 deletions

View File

@ -0,0 +1,97 @@
package cn.whaifree.interview.HS;
import java.util.Scanner;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/4/11 17:54
* @注释
*/
public class HS {
public static void main1(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext hasNextLine 的区别
int n = in.nextInt();
// 大于10 小于该n
for (int i = n; i > 10; i--) {
get(i);
}
}
/**
* 列举出小于小于max且长度为n的所有满足的数
* @param n
*/
public static void get(int n) {
// 获取n的长度
int length = 0;
int newN = n;
while (newN != 0) {
length++;
newN /= 10;
}
newN = n;
int res = 0;
while (newN > 0) {
int c = newN % 10;
newN /= 10;
res += Math.pow(c, length);
}
if (res == n) {
System.out.println(res);
}
}
public static void main(String[] args) {
double[] doubles = {3, 2, 6, 5, 1, 3};
System.out.println(get_max_profit(10000, 6, doubles, 2));
}
/**
* 代码中的类名方法名参数名已经指定请勿修改直接返回方法规定的值即可
*
* 根据输入计算最大收益
* @param M double浮点型 初始资金
* @param N int整型 历史价格天数
* @param historyPrices double浮点型一维数组 N天历史价格
* @param K int整型 最大允许交易次数
* @return double浮点型
*/
public static double get_max_profit (double M, int N, double[] historyPrices, int K) {
// write code here
// dp[0] 表示当天手里没有股票的手里的钱
// - 没有钱有两种
// dp[1] 表示手里有股票手里的钱
double[] buy = new double[K + 1];
double[] cell = new double[K + 1];
buy[0] = -historyPrices[0];
cell[0] = 0;
for (int i = 1; i <= K; i++) {
buy[i] = cell[i] = Integer.MIN_VALUE / 2;
}
for (int i = 1; i < N; i++) {
buy[0] = Math.max(buy[0], cell[0] - historyPrices[i]);
for (int j = 1; j <= K; j++) {
buy[j] = Math.max(buy[j], cell[j] - historyPrices[i]);
cell[j] = Math.max(cell[j], buy[j - 1] + historyPrices[i]);
}
}
// 不持有股票的最大利润 cell 累乘后扣除初始值
double res = 1;
for (double v : cell) {
if (v != 0) {
res *= v;
}
}
res *= M;
res -= M;
return res;
}
}

View File

@ -0,0 +1,206 @@
package cn.whaifree.leetCode.Dynamic;
import org.junit.Test;
/**
*
* 买卖股票的最佳时机 四题+变形
* @version 1.0
* @Author whai文海
* @Date 2024/4/12 11:46
* @注释
*/
public class Stock {
@Test
public void test()
{
// int[] prices = {7,1,5,3,6,4};
int[] prices = {1,2,3,4,5};
System.out.println(new LeetCode123_.Solution().maxProfit(prices));
}
}
class LeetCode188_{
class Solution {
public int maxProfit(int k, int[] prices) {
// dp[i][j] 表示第i天交易第k次的最大收益
// dp[i][0] 表示第i天第 0/2 +1 次持有的最大手头
// dp[i][1] 表示第i天第 1/2 +1次未持有的最大手头
int[][] dp = new int[prices.length][k * 2];
// 未持有 初始化
for (int i = 0; i < prices.length; i += 2) {
dp[i][0] = -prices[0];
}
for (int i = 0; i < prices.length; i++) {
for (int j = 0; j < k * 2; j++) {
}
}
return 1;
}
}
}
class LeetCode123_ {
static class Solution {
/**
* 最多可以完成 两笔 交易
* 你不能同时参与多笔交易你必须在再次购买前出售掉之前的股票
*
* dp[i][j] 表示第i天 状态j的最大手头有的钱
* 一天一共就有五个状态
* 0. 没有操作 其实我们也可以不设置这个状态
*
* 1. 第一次持有股票第i天持有第一次股票
* - 第i-1天就持有这个第一次股票 dp[i][1] = dp[i-1][1]
* - 第i天买入这个股票 dp[i][1] = dp[i-1][0] - prices[i]
* 2. 第一次不持有股票
* - 第i天卖出 dp[i][2] = dp[i-1][1]+price[i]
* - 第i-1天就不持有第一支 dp[i][2] = dp[i-1][2]
* 3. 第二次持有股票
* - 第i天买入第二支 dp[i][3] = dp[i-1][2] - price[i]
* - i-1天就持有 dp[i][3] = dp[i-1][3]
* 4. 第二次不持有股票
* - 第i天卖出第二支 dp[i][4] = dp[i-1][3] + price[i]
* - 第i-1天就没有 dp[i][4] = dp[i-1][4]
*
* @param prices
* @return
*/
public int maxProfit(int[] prices) {
int[][] dp = new int[prices.length][5];
dp[0][1] = -prices[0];
dp[0][3] = -prices[0];
for (int i = 1; i < prices.length; i++) {
// 没有操作手上的现金自然就是0
// dp[i][1] = Math.max(dp[i - 1][1], 0 - prices[i]);
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 dp[prices.length - 1][4];
}
public int maxProfit1(int[] prices) {
int[] dp = new int[5];
dp[1] = -prices[0];
dp[3] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[1] = Math.max(dp[1], dp[0] - prices[i]);
dp[2] = Math.max(dp[2], dp[1] + prices[i]);
dp[3] = Math.max(dp[3], dp[2] - prices[i]);
dp[4] = Math.max(dp[4], dp[3] + prices[i]);
}
return dp[4];
}
}
}
class LeetCode122_{
static class Solution {
public int maxProfit(int[] prices) {
// 只要递增就买入
int left = 0;
int right = 1;
int profit = 0;
while (right < prices.length) {
while (left < right && prices[left] > prices[right]) {
left++;
}
if (prices[left] < prices[right]) {
profit += (prices[right] - prices[left]);
left = right;
}
right++;
}
return profit;
}
}
static class Solution1 {
public int maxProfit(int[] prices) {
/**
* dp
* dp[i][0] 表示 i天没有股票的时候 手头的现金
* - i-1就没有 dp[i-1][0]
* - i天刚刚卖 dp[i-1][1]+price[i]
* dp[i][1] 表示 i天有股票的时候 手头的现金
* - i-1就有 dp[i-1][1]
* - 刚刚买入 dp[i-1][0] - price[i]
*/
int[][] dp = new int[prices.length][2];
dp[0][1] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[prices.length - 1][0];
}
}
}
class LeetCode121_ {
static class Solution {
public int maxProfit(int[] prices) {
// 最低点买入最高点卖出
int min = Integer.MAX_VALUE;
int res = 0;
for (int price : prices) {
min = Math.min(min, price);
res = Math.max(res, price - min);
}
return res;
}
}
static class Solution2 {
public int maxProfit(int[] prices) {
int[][] dp = new int[prices.length][2];
// 本题只能交易一次
// dp[i][0] 表示第i天手里没有股票的 手里的现金
// - 第i天卖出 dp[i][0]=dp[i-1][1]+prices[i]
// - 第i-1天就没有股票 dp[i][0]=dp[i-1][0]
// dp[i][1] 表示第i天手里有股票的 手里的现金
// - 第i天买入 dp[i][1] = - prices[i]
// - 第i-1天就有 dp[i][1] = dp[i-1][1]
dp[0][1] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], - prices[i]);
}
return dp[prices.length - 1][0];
}
}
static class Solution3 {
public int maxProfit(int[] prices) {
int[] dp = new int[2];
// 本题只能交易一次
// dp[i][0] 表示第i天手里没有股票的 手里的现金
// - 第i天卖出 dp[i][0]=dp[i-1][1]+prices[i]
// - 第i-1天就没有股票 dp[i][0]=dp[i-1][0]
// dp[i][1] 表示第i天手里有股票的 手里的现金
// - 第i天买入 dp[i][1] = - prices[i]
// - 第i-1天就有 dp[i][1] = dp[i-1][1]
dp[1] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[0] = Math.max(dp[0], dp[1] + prices[i]);
dp[1] = Math.max(dp[1], - prices[i]);
}
return dp[0];
}
}
}

View File

@ -1,5 +1,11 @@
package cn.whaifree.leetCode.LeetCode;
import org.junit.Test;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
/**
* @version 1.0
* @Author whai文海
@ -7,4 +13,65 @@ package cn.whaifree.leetCode.LeetCode;
* @注释
*/
public class LeetCode503 {
@Test
public void test()
{
int[] nums = {1,2,3,4,3};
Solution solution = new Solution();
int[] res = solution.nextGreaterElements(nums);
for (int i = 0; i < res.length; i++) {
System.out.println(res[i]);
}
}
class Solution {
/**
* 循环
* 1. 两倍拼接
* 2. 模拟走两遍
* @param nums
* @return
*/
public int[] nextGreaterElements(int[] nums) {
Deque<Integer> stack = new LinkedList<>();
stack.push(0);
int[] res = new int[nums.length];
Arrays.fill(res, -1);
for (int i = 1; i < nums.length * 2; i++) {
if (nums[stack.peek()] < nums[i % nums.length]) {
// 找到了栈顶比他大的值
while (!stack.isEmpty() && nums[stack.peek()] < nums[i % nums.length]) {
res[stack.peek()] = nums[i % nums.length];
stack.pop();
}
stack.push(i % nums.length);
} else if (nums[stack.peek()] > nums[i % nums.length]) {
stack.push(i % nums.length);
} else {
stack.push(i % nums.length);
}
}
return res;
}
public int[] nextGreaterElements1(int[] nums) {
Deque<Integer> stack = new LinkedList<>();
stack.push(0);
int[] res = new int[nums.length];
Arrays.fill(res, -1);
for (int i = 1; i < nums.length * 2; i++) {
// 找到了栈顶比他大的值
int h = i % nums.length;
while (!stack.isEmpty() && nums[stack.peek()] < nums[h]) {
res[stack.peek()] = nums[h];
stack.pop();
}
stack.push(h);
}
return res;
}
}
}

View File

@ -0,0 +1,111 @@
package cn.whaifree.leetCode.LeetCode;
import org.junit.Test;
import java.util.Deque;
import java.util.LinkedList;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/4/11 13:42
* @注释
*/
public class LeetCode84 {
@Test
public void test()
{
int[] heights = {0};
int i = new Solution1().largestRectangleArea(heights);
System.out.println(i);
}
class Solution {
public int largestRectangleArea(int[] heights) {
int[] left = new int[heights.length];
int[] right = new int[heights.length];
// 记录左右第一个小于i的坐标这样就能计算以heights[i]为高的面积
left[0] = -1;
for (int i = 1; i < heights.length; i++) {
int index = i - 1;
while (index >= 0 && heights[index] >= heights[i]) {
// index--; 这样会超时
index = left[index];
}
left[i] = index;
}
right[right.length - 1] = right.length;
for (int i = right.length - 2; i >= 0; i--) {
int index = i + 1;
while (index < right.length && heights[index] >= heights[i]) {
index = right[index];
}
right[i] = index;
}
// 获得左边右边比他小的第一个数就能计算最大面积
int max = Integer.MIN_VALUE;
for (int i = 0; i < left.length; i++) {
int sum = (right[i] - left[i] - 1) * heights[i];
max = Math.max(max, sum);
}
return max;
}
}
class Solution1 {
/**
* 找每个柱子左右两边第一个小于该柱子的柱子
*
* 找到凸的地方
*
* @param heights
* @return
*/
public int largestRectangleArea(int[] heights) {
// 数组扩容在头和尾各加入一个元素因为要计算以i为高的最大面积
int [] newHeights = new int[heights.length + 2];
newHeights[0] = 0;
newHeights[newHeights.length - 1] = 0;
for (int index = 0; index < heights.length; index++){
newHeights[index + 1] = heights[index];
}
heights = newHeights;
// 扩容是为了在计算最大矩形面积时能处理以下两种特殊情况
// 包含第一个柱子的最大矩形
// 包含最后一个柱子的最大矩形
Deque<Integer> stack = new LinkedList<>();
stack.push(0);
int res = 0;
for (int i = 1; i < heights.length; i++) {
if (heights[i] == heights[stack.peek()]) {
// 如果 栈顶 i
stack.push(i);
} else if (heights[i] < heights[stack.peek()]) {
// 4 栈顶[6 3...]
while (!stack.isEmpty() && heights[i] < heights[stack.peek()]) {
// 顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度
Integer mid = stack.pop(); // 凸的中间
if (!stack.isEmpty()) {
Integer left = stack.peek();
Integer right = i;
res = Math.max(res, (right - left - 1) * heights[mid]);
}
}
stack.push(i);
} else {
stack.push(i);
}
}
return res;
}
}
}

View File

@ -0,0 +1,31 @@
package cn.whaifree.test;
public class ThreadLocalExample {
public static void main(String[] args) throws InterruptedException {
for(int i=0 ; i<3; i++){
new Thread(new MyThread()).start();
}
}
}
class MyThread implements Runnable{
private static ThreadLocal<Integer> localVariable = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 100;
}
};
@Override
public void run() {
System.out.println("Thread Name= " + Thread.currentThread().getName() + " default value = " + localVariable.get());
//formatter pattern is changed here by thread, but it won't reflect to other threads
localVariable.set(localVariable.get() + 1);
System.out.println("Thread Name= " + Thread.currentThread().getName() + " localVariable = " + localVariable.get());
}
}