H2O生成
LeetCode1117题,分别有两个线程,一个线程产生H,一个线程产生O,保证每轮输出都能产生一个水分子,顺序不做限制。
现在有两种线程,氢 oxygen 和氧 hydrogen,你的目标是组织这两种线程来产生水分子。
存在一个屏障(barrier)使得每个线程必须等候直到一个完整水分子能够被产生出来。
氢和氧线程会被分别给予 releaseHydrogen 和 releaseOxygen 方法来允许它们突破屏障。
这些线程应该三三成组突破屏障并能立即组合产生一个水分子。
你必须保证产生一个水分子所需线程的结合必须发生在下一个水分子产生之前。
换句话说:
如果一个氧线程到达屏障时没有氢线程到达,它必须等候直到两个氢线程到达。
如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
书写满足这些限制条件的氢、氧线程同步代码。
示例 1:
输入: "HOH"
输出: "HHO"
解释: "HOH" 和 "OHH" 依然都是有效解。
示例 2:
输入: "OOHHHH"
输出: "HHOHHO"
解释: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" 和 "OHHOHH" 依然都是有效解。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/building-h2o
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路分析:
1.可以把每产生一个水分子看做一轮,每轮会有两个H线程和一个O线程执行。
2.控制每轮满足条件的线程执行,不满足的阻塞。
class H2O {
//创建一个Semaphore实例
private Semaphore semaphoreH = new Semaphore(2);
private Semaphore semaphoreO = new Semaphore(1);
//创建一个CyclicBarrier实例
private CyclicBarrier barrier=new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
//每完成一轮,就添加继续的条件
semaphoreH.release(2);
semaphoreO.release(1);
}
});
public H2O() {
}
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
try {
semaphoreH.acquire(1);
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
releaseHydrogen.run();
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
try {
semaphoreO.acquire(1);
// releaseOxygen.run() outputs "O". Do not change or remove this line.
releaseOxygen.run();
barrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
最大相等频率
一个数组里删掉一个数后,满足每个数出现的频率是一致的,求最大的长度
思路分析(题解杨添伦):
考虑四种满足条件的情况:
1.前缀数组中有两种频率次数的存在a和b,其中b=a+1
2.前缀数组中有两种频率次数的存在,只有一个数字出现了一次,其余的全部相同
3.整个数组里的数字频率都为1
4.整个数组里的数字都相同
/前缀数组
int[] pre = new int[100001];
//存储出现该次数有多少个数字
int[] count = new int[100001];
//最终返回的长度
int res = 0;
//当前数字出现的次数
int cur = 0;
for (int i = 0; i < nums.length; i++) {
//++pre[nums[i]]该数出现的频率+1
//count[++pre[nums[i]]]++出现该频率的数加1
count[++pre[nums[i]]]++;
//更新当前出现的最大频率
cur = Math.max(cur, pre[nums[i]]);
//1、4 2
if (count[cur - 1] * (cur - 1) == i || count[cur] * cur == i) {
res = i + 1;
}
}
//3
if (cur == 1) return nums.length;
return res;
编辑距离
LeetCode72题,给定三个操作将单词1替换成单词2,问最少操作的步骤。
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例 1:
输入: word1 = "horse", word2 = "ros"
输出: 3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
示例 2:
输入: word1 = "intention", word2 = "execution"
输出: 5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/edit-distance
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路分析:
经典的动态规划,首先别管现在两个单词的长度,都想象是长度0,很明显步骤为0,之后不断的根据上一个操作来得到最小操作数,当str1.length()=str2.length()+1时,只需获得str1.length()-1时的操作数+1即为最小操作数。
public static int minDistance(String word1, String word2) {
int len1 = word1.length();
int len2 = word2.length();
//用于存储不同长度时的操作数
//dp的意义为:word1.length=i word2.length=j时,最小操作数为dp[i][j]
int[][] dp = new int[len1 + 1][len2 + 1];
//当word2=""时,word1只需删掉对应的数
for (int i = 0; i <= len1; i++) {
dp[i][0] = i;
}
//当word1=""时,word1只需增加对应的数
for (int i = 0; i <= len2; i++) {
dp[0][i] = i;
}
for (int i = 1; i < len1; i++) {
for (int j = 1; j < len2; j++) {
//如果第i-1个字符相等,则两个字符都不用操作了,两个关键字的长度都退一个
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
//否则取word1.length()-1、word2.length()-1、word1.length()-1和word2.length()-1时的最小操作数+1
//这个+1意味着使用增加、删除、替换这三个步骤中的一个
dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1;
}
}
}
return dp[len1][len2];
}