This commit is contained in:
kkunkka
2025-06-09 16:09:52 +08:00
parent bb5e3d7ca2
commit 361355e3aa
5 changed files with 259 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
package com.dota.binarySearch._2071;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
class Solution {
public static void main(String[] args) {
new Solution().maxTaskAssign(new int[]{15, 10, 30}, new int[]{10, 10, 10}, 3, 10);
}
public int maxTaskAssign(int[] tasks, int[] workers, int pills, int strength) {
Arrays.sort(tasks);
Arrays.sort(workers);
int left = 0;
int right = Math.min(tasks.length, workers.length) + 1;
while (left + 1 < right) {
int mid = (left + right) >>> 1;
if (check(tasks, workers, pills, strength, mid)) {
left = mid;
} else {
right = mid;
}
}
return left;
}
private boolean check(int[] tasks, int[] workers, int pills, int strength, int k) {
int i = 0;
Deque<Integer> stack = new ArrayDeque<>();
for (int j = workers.length - k; j < workers.length; j++) {
int w = workers[j];
while(i < k && w + strength >= tasks[i]) {
stack.add(tasks[i]);
i++;
}
if (stack.isEmpty()) {
return false;
}
if (w >= stack.peekFirst()) {
stack.pollFirst();
continue;
}
if (pills ==0) {
return false;
}
pills--;
stack.pollLast();
}
return true;
}
}

View File

@@ -0,0 +1,43 @@
package com.dota.binarySearch._3007;
import java.util.HashMap;
import java.util.Map;
class Solution {
Map<Long, Long> map ;
public long findMaximumNumber(long k, int x) {
map = new HashMap<>();
long l = 1, r = (k + 1) << x;
while(l + 1 < r) {
long mid = l + (r - l) / 2;
if (check(k, x, mid)) {
l = mid;
} else {
r = mid;
}
}
return l;
}
boolean check(long k, int x, long num) {
long res = 0;
for (long i = 1; i <= num ; i++) {
res += df(i, x);
}
return res <= k;
}
// 计算n的价值
long df(long n ,int x) {
if (map.containsKey(n)) {
return map.get(n);
}
long res = 0;
n >>>= x-1;
while(n != 0) {
res += n&1;
n >>>= x;
}
map.put(n, res);
return res;
}
}

View File

@@ -0,0 +1,38 @@
package com.dota.binarySearch._78;
class Solution {
public static void main(String[] args) {
new Solution().rampartDefensiveLine(new int[][]{{0,3},{4,5},{7,9}});
}
public int rampartDefensiveLine(int[][] rampart) {
int n = rampart.length;
int l = 0, r = rampart[n - 1][1] + 1;
while(l+1<r){
int mid = l+(r-l)/2;
if (check(rampart, mid)) {
l = mid;
} else {
r = mid;
}
}
return l;
}
boolean check(int[][] rampart, int k) {
int l = rampart[1][0] - rampart[0][1];
int r;
for (int i = 1; i < rampart.length - 1; i++) {
r = rampart[i+1][0] - rampart[i][1];
if (l >= k) {
l = r;
continue;
}
r -= (k-l);
if (r < 0) {
return false;
}
l = r;
}
return true;
}
}

View File

@@ -0,0 +1,25 @@
package com.dota.deep._386;
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<Integer> lexicalOrder(int n) {
var res = new ArrayList<Integer>();
for (int i = 1; i < 10; i++) {
df(res, i, n);
}
return res;
}
void df(List<Integer> list, int num, int n) {
if (num > n) return;
list.add(num);
num *= 10;
for (int i = 0; i < 10; i++) {
num += i;
df(list, num, n);
num -= i;
}
}
}

View File

@@ -0,0 +1,98 @@
package com.dota.week._158;
import java.util.Arrays;
class Solution {
public int maximumProfit(int[] prices, int k) {
int n = prices.length;
// 处理边缘情况:如果没有价格数据或 k 为 0则无法进行交易利润为 0。
if (n == 0 || k == 0) {
return 0;
}
// 当 k 足够大时(例如 k >= n - 1意味着我们可以进行任意多次交易。
// 由于允许普通交易和做空交易,我们可以抓住任何价格波动来盈利。
// 例如,如果 prices[i+1] > prices[i],可以通过买入 prices[i] 卖出 prices[i+1] 赚取 prices[i+1] - prices[i]。
// 如果 prices[i+1] < prices[i],可以通过做空 prices[i] 买回 prices[i+1] 赚取 prices[i] - prices[i+1]。
// 两种情况下的利润都是 |prices[i+1] - prices[i]|。
// 因此,当 k 足够大时,最大利润是所有相邻价格绝对差的总和。
// 理论上n-1 是最大可能利用的“单步”价格变动机会。
if (k >= n - 1) {
int maxProfit = 0;
for (int i = 1; i < n; i++) {
maxProfit += Math.abs(prices[i] - prices[i - 1]);
}
return maxProfit;
}
// k 不够大,使用动态规划。
// 状态定义:
// noPos[j]: 完成 j 笔交易后,当前没有持仓的最大利润。
// hasLong[j]: 完成 j 笔交易后,当前持有多头仓位(即为第 j+1 笔普通交易买入)的最大利润。
// hasShort[j]: 完成 j 笔交易后,当前持有空头仓位(即为第 j+1 笔做空交易卖出)的最大利润。
// 初始化为极小的负数,表示不可达状态。
// 使用 Integer.MIN_VALUE / 2 来避免在加减价格时发生溢出。
final long INF = Long.MIN_VALUE / 2;
long[] noPos = new long[k + 1];
long[] hasLong = new long[k + 1];
long[] hasShort = new long[k + 1];
// 将所有状态初始化为不可达(负无穷大),除了初始基准状态。
Arrays.fill(noPos, INF);
Arrays.fill(hasLong, INF);
Arrays.fill(hasShort, INF);
// 第 0 天的初始状态:
noPos[0] = 0; // 完成 0 笔交易,无持仓,利润 0。
hasLong[0] = -prices[0]; // 完成 0 笔交易,买入第一支股票(开启第 1 笔普通交易),利润为 -prices[0]。
hasShort[0] = prices[0]; // 完成 0 笔交易,做空第一支股票(开启第 1 笔做空交易),利润为 prices[0]。
// 遍历每一天(从第 1 天开始到最后一天)
for (int i = 1; i < n; i++) {
int currentPrice = prices[i];
// 更新完成 0 笔交易的状态:
// noPos[0] 保持 0因为在没有交易的情况下无法产生利润。
// hasLong[0]: 保持原有长仓利润,或者在当前价格买入(开启第一笔交易)。
hasLong[0] = Math.max(hasLong[0], noPos[0] - currentPrice);
// hasShort[0]: 保持原有短仓利润,或者在当前价格做空(开启第一笔交易)。
hasShort[0] = Math.max(hasShort[0], noPos[0] + currentPrice);
// 遍历已完成的交易数 j从 1 到 k
for (int j = 1; j <= k; j++) {
// 保存当前 noPos[j] 的值,它代表了前一天的状态。
// 这一点很重要,因为 hasLong[j] 和 hasShort[j] 的计算需要基于前一天的 noPos[j]。
long prevNoPos_j = noPos[j];
// 更新 noPos[j]: 完成 j 笔交易,无持仓。
// 1. 保持不变(从前一天的 noPos[j] 保持)。
// 2. 从持有长仓状态hasLong[j-1])卖出,完成第 j 笔交易。
// 3. 从持有短仓状态hasShort[j-1])买回,完成第 j 笔交易。
// 注意hasLong[j-1] 和 hasShort[j-1] 在当前 j 的迭代中尚未被更新,因此它们代表的是前一天的状态。
noPos[j] = Math.max(noPos[j], hasLong[j-1] != INF ? hasLong[j-1] + currentPrice : INF);
noPos[j] = Math.max(noPos[j], hasShort[j-1] != INF ? hasShort[j-1] - currentPrice : INF);
// 更新 hasLong[j]: 完成 j 笔交易,当前持有长仓。
// 1. 保持不变(从前一天的 hasLong[j] 保持)。
// 2. 从无持仓状态prevNoPos_j即前一天的 noPos[j])买入,开始第 j+1 笔普通交易。
hasLong[j] = Math.max(hasLong[j], prevNoPos_j != INF ? prevNoPos_j - currentPrice : INF);
// 更新 hasShort[j]: 完成 j 笔交易,当前持有短仓。
// 1. 保持不变(从前一天的 hasShort[j] 保持)。
// 2. 从无持仓状态prevNoPos_j即前一天的 noPos[j])做空,开始第 j+1 笔做空交易。
hasShort[j] = Math.max(hasShort[j], prevNoPos_j != INF ? prevNoPos_j + currentPrice : INF);
}
}
// 最终结果是所有 noPos[j] 中的最大值,因为我们希望最终不持有任何仓位以获得最大利润。
long maxTotalProfit = 0; // 利润可以为 0不交易或负数所有交易都亏损
for (int j = 0; j <= k; j++) {
maxTotalProfit = Math.max(maxTotalProfit, noPos[j]);
}
return (int)maxTotalProfit;
}
}