「这是我参与2022首次更文挑战的第34天,活动详情查看:2022首次更文挑战」。
LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode
881. 救生艇
难度中等208收藏分享切换为英文接收动态反馈
给定数组 people
。people[i]
表示第 i
个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit
。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit
。
返回 承载所有人所需的最小船数 。
示例 1:
输入: people = [1,2], limit = 3
输出: 1
解释: 1 艘船载 (1, 2)
复制代码
示例 2:
输入: people = [3,2,2,1], limit = 3
输出: 3
解释: 3 艘船分别载 (1, 2), (2) 和 (3)
复制代码
示例 3:
输入: people = [3,5,3,4], limit = 5
输出: 4
解释: 4 艘船分别载 (3), (3), (4), (5)
复制代码
提示:
1 <= people.length <= 5 * 104
1 <= people[i] <= limit <= 3 * 104
class Solution {
public int numRescueBoats(int[] num, int limit) {
Arrays.sort(num);
int right = num.length - 1;
int left = 0;
int res = 0;
while (left <= right) {
if (num[left] + num[right] > limit) {
right--;
res++;
} else {
left++;
right--;
res++;
}
}
return res;
}
}
复制代码
883. 三维形体投影面积
难度简单66收藏分享切换为英文接收动态反馈
在 n x n
的网格 grid
中,我们放置了一些与 x,y,z 三轴对齐的 1 x 1 x 1
立方体。
每个值 v = grid[i][j]
表示 v
个正方体叠放在单元格 (i, j)
上。
现在,我们查看这些立方体在 xy
、yz
和 zx
平面上的投影。
投影 就像影子,将 三维 形体映射到一个 二维 平面上。从顶部、前面和侧面看立方体时,我们会看到“影子”。
返回 所有三个投影的总面积 。
示例 1:
输入: [[1,2],[3,4]]
输出: 17
解释: 这里有该形体在三个轴对齐平面上的三个投影(“阴影部分”)。
复制代码
示例 2:
输入: grid = [[2]]
输出: 5
复制代码
示例 3:
输入: [[1,0],[0,2]]
输出: 8
复制代码
提示:
n == grid.length == grid[i].length
1 <= n <= 50
0 <= grid[i][j] <= 50
class Solution {
public int projectionArea(int[][] grid) {
int[] x = new int[grid.length];
int[] y = new int[grid.length];
int n = grid.length;
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
x[i] = (int)Math.max(x[i], grid[i][j]);
y[j] = (int)Math.max(y[j], grid[i][j]);
if (grid[i][j] == 0) {
res--;
}
}
}
for (int i = 0; i < n; i++) {
res = res + x[i] + y[i];
}
return res + n*n;
}
}
复制代码
884. 两句话中的不常见单词
难度简单154收藏分享切换为英文接收动态反馈
句子 是一串由空格分隔的单词。每个 单词 **仅由小写字母组成。
如果某个单词在其中一个句子中恰好出现一次,在另一个句子中却 没有出现 ,那么这个单词就是 不常见的 **。
给你两个 句子 s1
和 s2
,返回所有 不常用单词 的列表。返回列表中单词可以按 任意顺序 组织。
示例 1:
输入: s1 = "this apple is sweet", s2 = "this apple is sour"
输出: ["sweet","sour"]
复制代码
示例 2:
输入: s1 = "apple apple", s2 = "banana"
输出: ["banana"]
复制代码
提示:
1 <= s1.length, s2.length <= 200
s1
和s2
由小写英文字母和空格组成s1
和s2
都不含前导或尾随空格s1
和s2
中的所有单词间均由单个空格分隔
class Solution {
public String[] uncommonFromSentences(String s1, String s2) {
String[] strs = s1.split(" ");
Map<String,Integer> map = new HashMap<String,Integer>();
for (String s : strs) {
map.put(s,map.getOrDefault(s,0) + 1);
}
strs = s2.split(" ");
for (String s : strs) {
map.put(s, map.getOrDefault(s,0) + 1);
}
List<String> list = new LinkedList<String>();
for (String s : map.keySet()) {
if (map.get(s) == 1) {
list.add(s);
}
}
return list.toArray(new String[list.size()]);
}
}
复制代码
885. 螺旋矩阵 III
难度中等74收藏分享切换为英文接收动态反馈
在 R
行 C
列的矩阵上,我们从 (r0, c0)
面朝东面开始
这里,网格的西北角位于第一行第一列,网格的东南角位于最后一行最后一列。
现在,我们以顺时针按螺旋状行走,访问此网格中的每个位置。
每当我们移动到网格的边界之外时,我们会继续在网格之外行走(但稍后可能会返回到网格边界)。
最终,我们到过网格的所有 R * C
个空间。
按照访问顺序返回表示网格位置的坐标列表。
示例 1:
输入: R = 1, C = 4, r0 = 0, c0 = 0
输出: [[0,0],[0,1],[0,2],[0,3]]
复制代码
示例 2:
输入: R = 5, C = 6, r0 = 1, c0 = 4
输出: [[1,4],[1,5],[2,5],[2,4],[2,3],[1,3],[0,3],[0,4],[0,5],[3,5],[3,4],[3,3],[3,2],[2,2],[1,2],[0,2],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[1,1],[0,1],[4,0],[3,0],[2,0],[1,0],[0,0]]
复制代码
提示:
1 <= R <= 100
1 <= C <= 100
0 <= r0 < R
0 <= c0 < C
class Solution {
public int[][] spiralMatrixIII(int R, int C, int r0, int c0) {
int[][] res = new int[R*C][2];
int[][] around = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int x = r0, y = c0, num = 1, dir = 0; //{x, y}为当前位置,num为当前查找的数字,dir为当前的方向
int Left = c0 - 1, Right = c0 + 1, Upper = r0 - 1, Bottom = r0 + 1; //四个方向的边界
while (num <= R * C) {
if (x >= 0 && x < R && y >= 0 && y < C) { //{x, y}位置在矩阵中
res[num - 1] = new int[]{x, y};
num++;
}
if (dir == 0 && y == Right) { //向右到右边界
dir += 1; //调转方向向下
Right += 1; //右边界右移
}
else if (dir == 1 && x == Bottom) { //向下到底边界
dir += 1;
Bottom += 1; //底边界下移
}
else if (dir == 2 && y == Left) { //向左到左边界
dir += 1;
Left--; //左边界左移
}
else if (dir == 3 && x == Upper) { //向上到上边界
dir = 0;
Upper--; //上边界上移
}
x += around[dir][0]; //下一个节点
y += around[dir][1];
}
return res;
}
}
复制代码
886. 可能的二分法
难度中等155收藏分享切换为英文接收动态反馈
给定一组 n
人(编号为 1, 2, ..., n
), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。
给定整数 n
和数组 dislikes
,其中 dislikes[i] = [ai, bi]
,表示不允许将编号为 ai
和 bi
的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true
;否则返回 false
。
示例 1:
输入: n = 4, dislikes = [[1,2],[1,3],[2,4]]
输出: true
解释: group1 [1,4], group2 [2,3]
复制代码
示例 2:
输入: n = 3, dislikes = [[1,2],[1,3],[2,3]]
输出: false
复制代码
示例 3:
输入: n = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
输出: false
复制代码
提示:
1 <= n <= 2000
0 <= dislikes.length <= 104
dislikes[i].length == 2
1 <= dislikes[i][j] <= n
ai < bi
dislikes
中每一组都 不同
class Solution {
ArrayList<Integer>[] list;
Map<Integer,Integer> color;
public boolean possibleBipartition(int n, int[][] bool) {
list = new ArrayList[n + 1];
color = new HashMap<Integer,Integer>();
for (int i = 0; i <= n; i++) {
list[i] = new ArrayList<Integer>();
}
for (int i = 0; i< bool.length; i++) {
list[bool[i][0]].add(bool[i][1]);
list[bool[i][1]].add(bool[i][0]);
}
for (int node = 1; node <= n; node++) {
if(!color.containsKey(node)) {
if(!dfs(node,0)) {
return false;
}
}
}
return true;
}
public boolean dfs(int node, int group) {
if(color.containsKey(node)) {
return color.get(node) == group;
}
color.put(node,group);
for (int i : list[node]) {
if(!dfs(i,group ^ 1)) {
return false;
}
}
return true;
}
}
复制代码
887. 鸡蛋掉落
难度困难748收藏分享切换为英文接收动态反馈
给你 k
枚相同的鸡蛋,并可以使用一栋从第 1
层到第 n
层共有 n
层楼的建筑。
已知存在楼层 f
,满足 0 <= f <= n
,任何从 高于 f
的楼层落下的鸡蛋都会碎,从 f
楼层或比它低的楼层落下的鸡蛋都不会破。
每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层 x
扔下(满足 1 <= x <= n
)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中 重复使用 这枚鸡蛋。
请你计算并返回要确定 f
确切的值 的 最小操作次数 是多少?
示例 1:
输入: k = 1, n = 2
输出: 2
解释:
鸡蛋从 1 楼掉落。如果它碎了,肯定能得出 f = 0 。
否则,鸡蛋从 2 楼掉落。如果它碎了,肯定能得出 f = 1 。
如果它没碎,那么肯定能得出 f = 2 。
因此,在最坏的情况下我们需要移动 2 次以确定 f 是多少。
复制代码
示例 2:
输入: k = 2, n = 6
输出: 3
复制代码
示例 3:
输入: k = 3, n = 14
输出: 4
复制代码
提示:
1 <= k <= 100
1 <= n <= 104
class Solution {
// public int superEggDrop(int K, int N) {
// if (N == 1) {
// return 1;
// }
// int[][] f = new int[N + 1][K + 1];
// for (int i = 1; i <= K; ++i) {
// f[1][i] = 1;
// }
// int ans = -1;
// for (int i = 2; i <= N; ++i) {
// for (int j = 1; j <= K; ++j) {
// f[i][j] = 1 + f[i - 1][j - 1] + f[i - 1][j];
// }
// if (f[i][K] >= N) {
// ans = i;
// break;
// }
// }
// return ans;
// }
public int superEggDrop(int K, int N) {
int[] dp = new int[K + 1];
int ans = 0; // 操作的次数
while (dp[K] < N){
for (int i = K; i > 0; i--) // 从后往前计算
dp[i] = dp[i] + dp[i-1] + 1;
ans++;
}
return ans;
}
}
复制代码
888. 公平的糖果交换
难度简单188收藏分享切换为英文接收动态反馈
爱丽丝和鲍勃拥有不同总数量的糖果。给你两个数组 aliceSizes
和 bobSizes
,aliceSizes[i]
是爱丽丝拥有的第 i
盒糖果中的糖果数量,bobSizes[j]
是鲍勃拥有的第 j
盒糖果中的糖果数量。
两人想要互相交换一盒糖果,这样在交换之后,他们就可以拥有相同总数量的糖果。一个人拥有的糖果总数量是他们每盒糖果数量的总和。
返回一个整数数组 answer
,其中 answer[0]
是爱丽丝必须交换的糖果盒中的糖果的数目,answer[1]
是鲍勃必须交换的糖果盒中的糖果的数目。如果存在多个答案,你可以返回其中 任何一个 。题目测试用例保证存在与输入对应的答案。
示例 1:
输入: aliceSizes = [1,1], bobSizes = [2,2]
输出: [1,2]
复制代码
示例 2:
输入: aliceSizes = [1,2], bobSizes = [2,3]
输出: [1,2]
复制代码
示例 3:
输入: aliceSizes = [2], bobSizes = [1,3]
输出: [2,3]
复制代码
示例 4:
输入: aliceSizes = [1,2,5], bobSizes = [2,4]
输出: [5,4]
复制代码
提示:
1 <= aliceSizes.length, bobSizes.length <= 104
1 <= aliceSizes[i], bobSizes[j] <= 105
- 爱丽丝和鲍勃的糖果总数量不同。
- 题目数据保证对于给定的输入至少存在一个有效答案。
class Solution {
public int[] fairCandySwap(int[] a, int[] b) {
int sumA = 0, sumB = 0;
boolean[] bool = new boolean[100001];
for (int i : a) {
sumA += i;
bool[i] = true;
}
for (int i : b) {
sumB += i;
}
int res = (sumA - sumB) / 2;
for (int i : b) {
if (i + res >= 0 && i + res <= bool.length && bool[i + res]) {
return new int[]{i + res,i};
}
}
return null;
}
}
复制代码
889. 根据前序和后序遍历构造二叉树
难度中等220收藏分享切换为英文接收动态反馈
给定两个整数数组,preorder
和 postorder
,其中 preorder
是一个具有 无重复 值的二叉树的前序遍历,postorder
是同一棵树的后序遍历,重构并返回二叉树。
如果存在多个答案,您可以返回其中 任何 一个。
示例 1:
输入: preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1]
输出: [1,2,3,4,5,6,7]
复制代码
示例 2:
输入: preorder = [1], postorder = [1]
输出: [1]
复制代码
提示:
1 <= preorder.length <= 30
1 <= preorder[i] <= preorder.length
preorder
中所有值都 不同postorder.length == preorder.length
1 <= postorder[i] <= postorder.length
postorder
中所有值都 不同- 保证
preorder
和postorder
是同一棵二叉树的前序遍历和后序遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode constructFromPrePost(int[] pre, int[] post) {
int n = pre.length;
if (n == 0) return null;
TreeNode node = new TreeNode(pre[0]);
if (n == 1) return node;
int left = 0;
for (int i = 0; i < n; i++) {
if (pre[1] == post[i]) {
left = i + 1;
}
}
node.left = constructFromPrePost(Arrays.copyOfRange(pre, 1, left + 1), Arrays.copyOfRange(post, 0, left));
node.right = constructFromPrePost(Arrays.copyOfRange(pre, left + 1, n), Arrays.copyOfRange(post, left, n - 1));
return node;
}
}
复制代码
890. 查找和替换模式
难度中等120收藏分享切换为英文接收动态反馈
你有一个单词列表 words
和一个模式 pattern
,你想知道 words
中的哪些单词与模式匹配。
如果存在字母的排列 p
,使得将模式中的每个字母 x
替换为 p(x)
之后,我们就得到了所需的单词,那么单词与模式是匹配的。
(回想一下,字母的排列是从字母到字母的双射:每个字母映射到另一个字母,没有两个字母映射到同一个字母。)
返回 words
中与给定模式匹配的单词列表。
你可以按任何顺序返回答案。
示例:
输入: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
输出: ["mee","aqq"]
解释: "mee" 与模式匹配,因为存在排列 {a -> m, b -> e, ...}。
"ccc" 与模式不匹配,因为 {a -> c, b -> c, ...} 不是排列。
因为 a 和 b 映射到同一个字母。
复制代码
提示:
1 <= words.length <= 50
1 <= pattern.length = words[i].length <= 20
class Solution {
public List<String> findAndReplacePattern(String[] words, String pattern) {
ArrayList<String> list = new ArrayList<String>();
for (String s : words) {
if (compare(s,pattern)) {
list.add(s);
}
}
return list;
}
public boolean compare(String s1, String s2) {
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
Map<Character, Character> map = new HashMap<Character, Character>();
for (int i = 0; i < str1.length; i++) {
if (!map.containsKey(str1[i])) map.put(str1[i], str2[i]);
if (map.get(str1[i]) != str2[i]) return false;
}
boolean[] bool = new boolean[26];
for (char c : map.values()) {
if(bool[c - 'a']) return false;
bool[c-'a'] = true;
}
return true;
}
}
复制代码