modify code

master
algorithmzuo 2 years ago
parent 25ca0edcda
commit e8d2eae9e7

@ -0,0 +1,115 @@
package class_2023_07_3_week;
// 先来一个最近学员在国外面试的题
// 有一个由x轴和y轴组成的坐标系
// "y下"和"y上"表示一条无限延伸的道路,"y下"表示这个道路的下限,"y上"表示这个道路的上限
// 给定一批长方形,每一个长方形有(x1, x2, y1, y2)4个坐标可以表示一个长方形
// 判断这条道路整体是不是可以走通的
// 以下为正式题目
// 图片在计算机处理中往往是使用二维矩阵来表示的
// 给你一个大小为 m x n 的二进制矩阵 image 表示一张黑白图片0 代表白色像素1 代表黑色像素
// 黑色像素相互连接,也就是说,图片中只会有一片连在一块儿的黑色像素。像素点是水平或竖直方向连接的
// 给你两个整数 x 和 y 表示某一个黑色像素的位置
// 请你找出包含全部黑色像素的最小矩形(与坐标轴对齐),并返回该矩形的面积
// 你必须设计并实现一个时间复杂度低于 O(m*n) 的算法来解决此问题。
// 测试链接 : https://leetcode.cn/problems/smallest-rectangle-enclosing-black-pixels/
public class Code01_SmallestRectangleEnclosingBlackPixels {
public static int minArea(char[][] image, int x, int y) {
int left = left(image, y);
int right = right(image, y);
int up = up(image, x, left, right);
int down = down(image, x, left, right);
return (right - left + 1) * (down - up + 1);
}
public static int left(char[][] image, int col) {
// .....左?....... col
int l = 0, r = col - 1, m, ans = col;
boolean find;
while (l <= r) {
m = (l + r) / 2;
find = false;
for (int i = 0; i < image.length; i++) {
if (image[i][m] == '1') {
find = true;
break;
}
}
if (find) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
public static int right(char[][] image, int col) {
int l = col + 1, r = image[0].length - 1, m, ans = col;
boolean find;
while (l <= r) {
m = (l + r) / 2;
find = false;
for (int i = 0; i < image.length; i++) {
if (image[i][m] == '1') {
find = true;
break;
}
}
if (find) {
ans = m;
l = m + 1;
} else {
r = m - 1;
}
}
return ans;
}
public static int up(char[][] image, int row, int left, int right) {
int u = 0, d = row - 1, m, ans = row;
boolean find;
while (u <= d) {
m = (u + d) / 2;
find = false;
for (int i = left; i <= right; i++) {
if (image[m][i] == '1') {
find = true;
break;
}
}
if (find) {
ans = m;
d = m - 1;
} else {
u = m + 1;
}
}
return ans;
}
public static int down(char[][] image, int row, int left, int right) {
int u = row + 1, d = image.length - 1, m, ans = row;
boolean find;
while (u <= d) {
m = (u + d) / 2;
find = false;
for (int i = left; i <= right; i++) {
if (image[m][i] == '1') {
find = true;
break;
}
}
if (find) {
ans = m;
u = m + 1;
} else {
d = m - 1;
}
}
return ans;
}
}

@ -0,0 +1,32 @@
package class_2023_07_3_week;
// 一个句子是由一些单词与它们之间的单个空格组成
// 且句子的开头和结尾没有多余空格
// 比方说,"Hello World" "HELLO" "hello world hello world" 都是句子
// 每个单词都 只 包含大写和小写英文字母
// 如果两个句子 sentence1 和 sentence2
// 可以通过往其中一个句子插入一个任意的句子(可以是空句子)而得到另一个句子
// 那么我们称这两个句子是 相似的
// 比方说sentence1 = "Hello my name is Jane"
// 且 sentence2 = "Hello Jane"
// 我们可以往 sentence2 中 "Hello" 和 "Jane" 之间插入 "my name is"
// 得到 sentence1
// 给你两个句子 sentence1 和 sentence2
// 如果 sentence1 和 sentence2 是相似的,请你返回 true ,否则返回 false
// 测试链接 : https://leetcode.cn/problems/sentence-similarity-iii/
public class Code02_SentenceSimilarityIII {
public static boolean areSentencesSimilar(String s1, String s2) {
String[] w1 = s1.split(" ");
String[] w2 = s2.split(" ");
int i = 0, j = 0, n1 = w1.length, n2 = w2.length;
while (i < n1 && i < n2 && w1[i].equals(w2[i])) {
i++;
}
while (n1 - j > i && n2 - j > i && w1[n1 - 1 - j].equals(w2[n2 - 1 - j])) {
j++;
}
return i + j == Math.min(n1, n2);
}
}

@ -0,0 +1,131 @@
package class_2023_07_3_week;
// 每一种货币都给定面值val[i]和拥有的数量cnt[i]
// 想知道目前拥有的货币在钱数为1、2、3...m时能找零成功的钱数有多少
// 也就是说当钱数的范围是1~m返回这个范围上有多少可以找零成功的钱数
// 比如只有3元的货币数量是5张
// m = 10
// 那么在1~10范围上只有钱数是3、6、9时可以成功找零
// 所以返回3表示有3种钱数可以找零成功
// 测试链接 : http://poj.org/problem?id=1742
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下的code提交时请把类名改成"Main",可以直接通过
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
public class Code03_CanChangeMoneyNumbers {
public static int MAXN = 101;
public static int[] val = new int[MAXN];
public static int[] cnt = new int[MAXN];
public static int MAXM = 100001;
public static boolean[] dp = new boolean[MAXM];
public static int n, m;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
n = (int) in.nval;
in.nextToken();
m = (int) in.nval;
if (n != 0 || m != 0) {
for (int i = 1; i <= n; i++) {
in.nextToken();
val[i] = (int) in.nval;
}
for (int i = 1; i <= n; i++) {
in.nextToken();
cnt[i] = (int) in.nval;
}
out.println(compute());
} else {
out.flush();
}
}
}
public static int compute() {
Arrays.fill(dp, 1, m + 1, false);
dp[0] = true;
// 每一种货币,遍历
for (int i = 1; i <= n; i++) {
if (cnt[i] == 1) {
// // 等于当前货币就1张
for (int j = m; j >= val[i]; j--) {
if (dp[j - val[i]]) {
dp[j] = true;
}
}
} else if (val[i] * cnt[i] > m) {
// 等于当前货币无限张
for (int j = val[i]; j <= m; j++) {
if (dp[j - val[i]]) {
dp[j] = true;
}
}
} else {
// 既不是1张也不是无限张
for (int mod = 0; mod < val[i]; mod++) {
// val[i] = 3元
// 0 : ....
// 1 : ....
// 2 : ....
int trueCnt = 0;
// 0 : m元 m-3元 m-6元 m-9元
// 1 : m-1元 m-4元 m-7元 m-10元
// 2 : m-2元
//
// 3元4张
//
//
// 9 12 【15 18 21 24】
//
for (int j = m - mod, size = 0; j >= 0 && size <= cnt[i]; j -= val[i], size++) {
trueCnt += dp[j] ? 1 : 0;
}
// // 9 12 【15 18 21 24】
// 9 【12 15 18 21】 24
// 每次窗口出去一个下标
// 进来一个下标
for (int j = m - mod, l = j - val[i] * (cnt[i] + 1); j >= 1; j -= val[i], l -= val[i]) {
// dp[j] = 上一行的值
// dp[j] 更新成 本行的值
if (dp[j]) {
trueCnt--;
} else {
if (trueCnt != 0) {
dp[j] = true;
}
}
if (l >= 0) {
trueCnt += dp[l] ? 1 : 0;
}
}
}
}
}
int ans = 0;
for (int i = 1; i <= m; i++) {
if (dp[i]) {
ans++;
}
}
return ans;
}
}

@ -0,0 +1,110 @@
package class_2023_07_3_week;
import java.util.ArrayList;
import java.util.PriorityQueue;
// 我们把无限数量的栈排成一行,按从左到右的次序从 0 开始编号
// 每个栈的的最大容量 capacity 都相同。实现一个叫「餐盘」的类 DinnerPlates
// DinnerPlates(int capacity) - 给出栈的最大容量 capacity
// void push(int val) 将给出的正整数 val 推入 从左往右第一个 没有满的栈
// int pop() 返回 从右往左第一个 非空栈顶部的值,并将其从栈中删除
// 如果所有的栈都是空的,请返回 -1。
// int popAtStack(int index) - 返回编号 index 的栈顶部的值,并将其从栈中删除
// 如果编号 index 的栈是空的,请返回 -1。
// 测试链接 : https://leetcode.cn/problems/dinner-plate-stacks/
public class Code04_DinnerPlateStacks {
class DinnerPlates {
// 根据题目数据量leetcode升级数据改大
private final int N = 100001;
private int capacity;
// 所有栈的结构
private ArrayList<ArrayList<Integer>> stacks = new ArrayList<>();
// 每个栈里有多少数字
private int[] cnt = new int[N + 1];
// 曾经满了然后又因为popAtStack方法变得不满的栈
// 编号放在这个堆里,小根堆
// 可以理解为空洞栈组成的堆
private PriorityQueue<Integer> heap = new PriorityQueue<>();
// 拥有数字的栈中,最右栈的编号
private int rightStack;
public DinnerPlates(int cap) {
capacity = cap;
rightStack = 0;
}
// 从右往左拿数,
public int pop() {
while (cnt[rightStack] == 0 && rightStack > 0) {
rightStack--;
}
if (cnt[rightStack] == 0) {
// 来到0号站还没遇到数字
return -1;
}
return stacks.get(rightStack).remove(--cnt[rightStack]);
}
public int popAtStack(int index) {
if (cnt[index] == 0) {
return -1;
}
int ans = stacks.get(index).remove(cnt[index] - 1);
if (cnt[index] == capacity) {
heap.add(index);
}
cnt[index]--;
return ans;
}
// push、pop、popAt
public void push(int val) {
if (heap.isEmpty()) {
// 没有空洞
// 0.....rightstack
if (cnt[rightStack] == capacity && rightStack < N) {
rightStack++;
}
if (stacks.size() == rightStack) {
stacks.add(new ArrayList<>());
}
stacks.get(rightStack).add(val);
cnt[rightStack]++;
} else {
// 有空洞
// rightStack往左来到该去的位置往左缩
while (cnt[rightStack] == 0 && rightStack > 0) {
rightStack--;
}
if (heap.peek() >= rightStack) {
// 所有空洞,没用了
while (!heap.isEmpty()) {
heap.poll();
}
// 0.....rightStack
if (cnt[rightStack] == capacity) {
rightStack++;
}
if (stacks.size() == rightStack) {
stacks.add(new ArrayList<>());
}
stacks.get(rightStack).add(val);
cnt[rightStack]++;
} else {
// 不是所有空洞都失效
int cur = heap.peek();
cnt[cur]++;
stacks.get(cur).add(val);
if (cnt[cur] == capacity) {
heap.poll();
}
}
}
}
}
}

@ -0,0 +1,31 @@
package class_2023_07_3_week;
// 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先
// 测试链接 : https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/
public class Code05_LowestCommonAncestorOfBinarySearchTree {
// 不提交这个类
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
}
// 提交以下的方法
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// root从上到下
// 如果先遇到了p说明p是答案
// 如果先遇到了q说明q是答案
// 如果root在p和q的值之间不用管p和q谁大谁小只要root在中间那么此时的root就是答案
// 如果root在p和q的值的左侧那么root往右移动
// 如果root在p和q的值的右侧那么root往左移动
while (root.val != p.val && root.val != q.val) {
if (Math.min(p.val, q.val) < root.val && root.val < Math.max(p.val, q.val)) {
break;
}
root = root.val < Math.min(p.val, q.val) ? root.right : root.left;
}
return root;
}
}

@ -4130,6 +4130,66 @@ forceField[i] = [x,y,side]
第077节 2023年7月3周流行算法题目解析
先来一个最近学员在国外面试的题
有一个由x轴和y轴组成的坐标系
"y下"和"y上"表示一条无限延伸的道路,"y下"表示这个道路的下限,"y上"表示这个道路的上限
给定一批长方形,每一个长方形有(x1, x2, y1, y2)4个坐标可以表示一个长方形
判断这条道路整体是不是可以走通的
以下为正式题目
图片在计算机处理中往往是使用二维矩阵来表示的
给你一个大小为 m x n 的二进制矩阵 image 表示一张黑白图片0 代表白色像素1 代表黑色像素
黑色像素相互连接,也就是说,图片中只会有一片连在一块儿的黑色像素。像素点是水平或竖直方向连接的
给你两个整数 x 和 y 表示某一个黑色像素的位置
请你找出包含全部黑色像素的最小矩形(与坐标轴对齐),并返回该矩形的面积
你必须设计并实现一个时间复杂度低于 O(m*n) 的算法来解决此问题。
测试链接 : https://leetcode.cn/problems/smallest-rectangle-enclosing-black-pixels/
一个句子是由一些单词与它们之间的单个空格组成
且句子的开头和结尾没有多余空格
比方说,"Hello World" "HELLO" "hello world hello world" 都是句子
每个单词都 只 包含大写和小写英文字母
如果两个句子 sentence1 和 sentence2
可以通过往其中一个句子插入一个任意的句子(可以是空句子)而得到另一个句子
那么我们称这两个句子是 相似的
比方说sentence1 = "Hello my name is Jane"
且 sentence2 = "Hello Jane"
我们可以往 sentence2 中 "Hello" 和 "Jane" 之间插入 "my name is"
得到 sentence1
给你两个句子 sentence1 和 sentence2
如果 sentence1 和 sentence2 是相似的,请你返回 true ,否则返回 false
测试链接 : https://leetcode.cn/problems/sentence-similarity-iii/
每一种货币都给定面值val[i]和拥有的数量cnt[i]
想知道目前拥有的货币在钱数为1、2、3...m时能找零成功的钱数有多少
也就是说当钱数的范围是1~m返回这个范围上有多少可以找零成功的钱数
比如只有3元的货币数量是5张
m = 10
那么在1~10范围上只有钱数是3、6、9时可以成功找零
所以返回3表示有3种钱数可以找零成功
测试链接 : http://poj.org/problem?id=1742
我们把无限数量的栈排成一行,按从左到右的次序从 0 开始编号
每个栈的的最大容量 capacity 都相同。实现一个叫「餐盘」的类 DinnerPlates
DinnerPlates(int capacity) - 给出栈的最大容量 capacity
void push(int val) 将给出的正整数 val 推入 从左往右第一个 没有满的栈
int pop() 返回 从右往左第一个 非空栈顶部的值,并将其从栈中删除
如果所有的栈都是空的,请返回 -1。
int popAtStack(int index) - 返回编号 index 的栈顶部的值,并将其从栈中删除
如果编号 index 的栈是空的,请返回 -1。
测试链接 : https://leetcode.cn/problems/dinner-plate-stacks/
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先
测试链接 : https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/

Loading…
Cancel
Save